                               MidiShare
                         Developer Documentation
                             version 1.67


                           English Alpha draft





Foreword
                                                                                           

MidiShare is a multi-tasking, real-time software environment, 
specially devised for the developing of MIDI applications with 
a triple target :

    To propose solutions to currently met problems when developing  
    any MIDI application : MIDI communication, synchronisation and 
    time management, task management and memory management. 

    To enable the real-time and multi-tasking functioning of these 
    applications, i.e. to enable the sharing of all the necessary 
    resources and their simultaneous access.

    To make easier cooperation between independent MIDI applications 
    by  proposing a real-time mechanism of inter-application 
    communications.

The present document is intended for developers who wish to use 
MidiShare for the writing of MIDI applications. They will find here 
a complete description of all the MidiShare functions and procedures, 
as well as all the data structures in use.

Yann Orlarey and Herv Lequay                   






/~INTRODUCTION
                                                     

/#About MidiShare

The availability of multi-tasking operating systems such as 
Multi-Finder, Unix and OS/2 on microcomputers is a decisive 
advantage in many application areas and offers real gains in 
term of power and ease of use.

Unfortunately, until now musicians have hardly benefited at all 
from the advantages of such systems due to the lack of music 
applications capable of running simultaneously in real  time on 
a single machine. The internal layers of a Midi program often
make use of critical resources of the computer such as timers, 
interrupts and serial link controllers which cannot be directly 
shared by more than one application, in addition, even multi-tasking 
operating systems are not generally a guarantee that applications 
run in real time.

Midishare came into existence from this observation with the ambition 
to provide the frame needed to develope musical applications in a
multi-tasks and real time context. When defining MidiShare, we have 
tried to conciliate three aims :

To propose solutions to the problems regularly met with in the 
 development of all Midi applications.

To permit the simultaneous running of these applications, 
 especially as regards real-time routines and Midi communications.

To allow for a cooperation between separately developed applications.

We are going to see how the various tools and services proposed by 
MidiShare comply with these objectives.


/#Events Managing

The whole system is based on the notion of event. An event is a 
dated entity possessing the informations for its own execution. 
The applications developed with MidiShare heavily relie on events 
to transmit and receive Midi messages but also to remember the tasks 
to be carried out.

It is generally not possible to use the host Operating System Memory 
Manager (MM) to deal with the allocation-deallocation of these events, 
since it revealed unadapted to a real-time context, non reentrant and 
inefficient, in terms of memory space when dealing with small zones 
of a few bytes. 

To make up for these lacks, MidiShare has its own dynamic memory 
allocation module, adapted to real-time constraints. For example, 
some functions permit to create or delete events (under interrupt too) 
with an extremely brief and constant time response.
Moreover, these events can be accessed to and handled in a uniform 
and orthogonal way by a small number of routines which take 
automatically in charge the various memory structures (for, let us 
say, a constant size Key On and a variable size System Exclusive).


/#Communicating

The second essential point is the communications achievement. 
The applications running under Midishare are not in charge of the 
communications physical execution but only deal with receiving and 
sending high-level events, for instance, complete Midi messages.
In fact, MidiShare is internally in charge of translating events 
into corresponding Midi bytes sequences. Each application receives 
events into its own reception fifo. The application can consult 
this fifo anytime, extract and process the events waiting for 
treatment. Sending out events is easy as well. Stating the required 
output time and event to be transmitted will be sufficient. 

Midi multiple ports can of course be used. On some softwares, 
Midi Channels are numbered from 0 to 31 so as to take into account 
the two ports which can be used on Macintosh computers. We thought 
preferable to separate these two informations. This way, each 
Midishare event has a channel number from 0 to 15 and a port number 
from 0 to 255; in the future, this will permit to deal with 
numerous Midi lines.


/#Time managing

It is obvious that a precise time control is essential for music. 
It is obvious too that according to the type of musical work 
carried out, different time representations are needed; which is 
why we chose the well-tried general solution consisting in an 
absolute representation of time in milliseconds over which other 
more musical representations can be built up by applications.

A 32 bits field defines the time for each MidiShare event. This 
field mentions the arrival time for the events received by an 
application or the required transmission time for events sent 
out by an application.

The algorithm used to manage the events scheduling is of course 
critical to the system's performances. Several methods have been 
proposed. In this particular case, we have used an algorithm 
developed at first by one of the authors for MidiLisp. This very 
efficient algorithm ensures in all cases a bounded scheduling 
and dispatching time for treated events.

MidiShare can be synchronised to external Midi Time Code. In this 
case the MidiShare internal time unit accuratly follow the speed 
variations of the external Midi Time Code. Midi applications can be 
automatically informed when MidiShare start and stop being locked to 
external Midi Time Code.


/#Tasks managing

Not only Midi messages are managed by MidiShare. Actually, an 
application having to remind a task to be done at a precise 
moment, can send to itself a particular type of message containing 
all the informations required for this task to be carried out.
When arrived at maturity, this internal event is set by MidiShare 
in the application's reception fifo as if it were an external event. 
The application's reception routine will then accomplish the required 
task.

A second mechanism is implemented by MidiShare for tasks management. 
It is much more procedural and actually, very similar to Moxie's 
cause. It is in fact a delayed procedure call. For this to be done, 
MidiShare collects all the call parameters, together with the address
of the routine to be called and generates a specific internal event. 
When this event has come to maturity, MidiShare restores the 
application context and actually deals with the call. It is to be 
noted that this call is made under interrupts, which means that some 
precautions have to be taken.

A third point related with tasks managing is the possibility for an 
application to define a reception alarm. It is a routine whose 
application gives MidiShare the address and which will be called 
each time new events are received (see example). Alarm therefore 
avoid an application having to consult periodically its reception 
fifo. Moreover, being called under interrupts, they allow for very 
efficient time responses.


/#Linking applications

As explained in the introduction, the reason for the creation of 
MidiShare was to permit several independant Midi applications to 
run simultaneously and to collaborate if necessary. This target 
may initially seem paradoxical. On the one hand, giving very 
application the impression to be the only user of the computer 
and consequently lessening the applications common resources. 
On the other hand, trying to connect these applications.

To isolate the applications was not a very difficult task. For 
instance, as regards incoming Midi messages, each application 
receives a different copy of them. Besides, every application 
possesses its own filters and reception fifo. There are no problems
either to merge the various message transmissions, since they occur 
at the logical level too. Finally, as regards time, all applications 
refer to the same absolute clock in milliseconds, without having any 
influence on it.

How can we now link these applications ? Many users undoubtedly 
experienced Midi informations transfers, of musical sequences 
for instance, between two computers. We have taken over this idea 
and implemented inside MidiShare an internal real-time communication 
mechanism between applications.

Let us take a concrete example: two applications, the first being an 
echo generator, the second a sequencer. By default, these two 
applications are connected to the actual Midi I/O. However, it is 
quite possible to connect the output of the echo generator to the 
input of the sequencer. Each application is not aware of the 
connection change. 

There is no constraint in the way to connect applications between 
themselves. In particular, it is possible for an application to 
have multiple sources and multiple destinations, or else to be 
connected to itself (for example a sequencer recording itself). 
Furthermore, these connections can be dynamically reconfigured while 
the applications are running.


/~OVERVIEW

                                                     
/#Opening and Closing MidiShare.

First of all, an application must make sure that MidiShare is 
in memory. This checking is done thanks to the MidiShare function.

Then, you must call the MidiOpen installation function. This routine 
allows to record some information relative to the application 
context (its name, the value of A5 register, etc...), to affect 
a reception FIFO and to attribute a unique reference number to the 
application.

As a counterpart to any MidiOpen call, the application must call the 
MidiClose function before leaving, by giving its reference number as 
an argument. MidiShare can thus be aware of the precise number of 
active Midi applications. In theory, there is no objection to an 
application doing several MidiOpen, under the condition it realizes 
as many MidiClose. In all, there must not be more than 63 
simultaneously opened Midi applications .

As long as no MidiOpen application is done, MidiShare is asleep and 
has no influence on the computer functioning. Following the first 
MidiOpen, MidiShare becomes active, it creates a task which will be 
called by an interruption  every  millisecond,  then  it  initiates  
Acia interruption vectors and registers corresponding to Midi ports. 
MidiShare returns inactive after the last MidiClose.


/#Communications et Connections
 
For an application to be able to emit and receive events, it must 
first connect to a source and a destination. In fact, MidiShare is 
built on an internal communication mechanism allowing to exchange 
in real-time Midi events between active application. An application
is like a black box, receiving a flow of events in entry and 
producing a flow of events in output. This black box can be freely 
connected to other black boxes, thus forming an arbitrarily complex 
network. This is one of the major points of MidiShare,  that allows 
a form of transparent and powerful collaboration between 
applications otherwise totally independent. 

"Real" Midi ins and outs are represented by a pseudo-application, 
which is always refered to as number 0 and named "MidiShare", with 
which you just have to connect to communicate with the outside.

The implementation of these connections is very simple. 
The MidiConnect procedure allows to switch on or off a connection 
between a source application and a destination application. 
The MidiIsConnected function gives the state (on or off) of a 
connection. There is no restriction to the establishing of 
connections, an application can be source or destination as many 
times as you wish. Loops are permitted.

In some special cases, it is important that an application may get 
information on the other active MidiShare applications. 
The MidiCountAppls function gives the number of open  Midi 
applications. The MidiGetIndAppl function allows to know the 
reference number of any application by giving its order number
(included between 1 and MidiCountAppls). It is also possible to 
find the reference number of an application thanks to its name 
using the MidiGetNamedAppl function. In the same way, knowing an 
application reference number, it is possible to find its name using 
the MidiGetName function. At last, the MidiSetName procedure allows 
to change the name of an application.

To be able to write more easily some "meta-applications" for the 
management of connections and other applications,  permanent 
information on context modifications into MidiShare (opening of 
new  applications,  changing connections, etc...)  is  highly
requested. To do so, you just have to define a context alarm thanks 
to MidiSetApplAlarm and MidiGetApplAlarm routines. This alarm will 
be automatically called by MidiShare to inform the application of 
all the occured changes.


/#Sending and receiving
  
Once the connections have been established, the application can 
send and receive Midi events. Each application owns a reception 
fifo  in which MidiShare puts a copy of the received events. 
These come from other applications or from the different Midi ports
in activity. MidiShare can in theory handle up to 256 ports. The 
implementation of Midi ports is controlled by the MidiSetPortState 
and MidiGetPortState routines. These must be used with care since 
they affect all the applications.

The MidiCountEvs function allows at any moment to know the number 
of events waiting in the reception fifo. This number is only 
limited by the memory size available for MidiShare. The events at 
disposal are picked up by repeated appeals to MidiGetEv function.
The MidiAvailEv function is almost similar. It allows to read a 
received event, while leaving it in the fifo. The MidiFlushEvs 
procedure eliminates all the events on wait in the reception fifo.

The events received by an application are copies. The application 
can therefore freely dispose of them without any repercussion on 
the other applications. However, it must not forget to free them 
when it no longer needs them.

Each application can select the events to be received by using a 
filter. The filtering process is local to the application and has 
no influence on the events received by the other applications. 
The implementation of these filters is achieved by two routines : 
MidiSetFilter and MidiGetFilter.

MidiShare drives an internal absolute clock on 32 bits which is 
automatically switched on with the first MidiOpen and keeps running 
until the last MidiClose. This clock is used to date (in milliseconds) 
all the received events, as well as to specify the sending dates of 
events to be transmitted. Moreover, it provides all the applications 
with an absolute time reference. Its value can be read by the 
MidiGetTime function. 

Three routines allow to manage the transmissions. The MidiSendIm 
procedure allows the immediate emission of an event. The MidiSend 
and MidiSendAt procedures allow time delayed emissions, MidiShare 
automatically taking in charge the effective emission at the 
scheduled time (thanks to that mechanism, an application can easily  
foresee emissions as accurately as to the millisecond and many days 
in advance).

Once an event is sent (by the means of MidiSend, MidiSendAt or 
MidiSendIm functions), it is no longer accessible by the 
application. This event must no longer be refered to, under threat 
of irremediable desorganisation of the system. 

Example of what you must not do :

e = MidiNewEv (typeNote); /* Typical example of fatal error   */
MidiSendIm(myRefNum, e);  /* after having being sent,         */
f = MidiCopyEv(e);        /* the 'e' pointer no longer refers */
                          /* to any valid event               */



/#Event managing

The memory management of a standard application is generally achieved 
by the computer "Memory Manager" (MM). The MM deals with dynamic 
allocation and freeing memory blocks of arbitrarily length, as well 
as memory compaction when necessary (excessive fragmentation of the 
memory). Unfortunately, a traditional MM is proved unadapted to a 
real time context. As a matter of fact :

 Only large blocks can be allocated efficiently by traditional MM. 
  For example, the Macintosh MM needs 12 more bytes by allocated 
  blocks, which is prohibitive for the very small group of bytes 
  represented by a Midi event.

 The allocation time of a block is not constant, but depends on 
  many factors, one of which being the fragmentation state of the 
  memory. It can be very long if a memory compaction proves necessary. 
  A traditional MM cannot guarantee the response time.

 A traditional MM is not re-entrant. No routine under interruption 
  can  therefore  use  it  directly  or  undirectly, without 
  irremediably desorganising the memory space.

To overcome these inadaptations, MidiShare holds its own memory 
manager, adapted to the Midi event management and available under 
interruption. MidiShare drives a group of events common to all the 
applications. Each event has compulsory fields (date, channel, port, 
type, etc...) and variable fields that depend of its type.

The allocation is very easily done by MidiNewEv function which 
returns an event of a suitable type. The disallocation is as easily 
done by the MidiFreeEv procedure.  An other way of allocating an 
event is to duplicate an existing event by the MidiCopyEv function. 
It is possible to know at every moment the available space left by 
the MidiFreeSpace function.

The access to the compulsory fields of the event is directly done. 
But the access to the variable fields is achieved thru the 
MidiSetField and MidiGetField functions. 

Some categories of events do not have a fixed number of fields. 
Such is the case, for example, for the Exclusive System messages. 
The MidiCountFields function gives the number of variable fields 
of an event. The MidiAddField procedure allows to add a field at 
the tail of an event of variable length.

For some special treatments, it may be useful to have access to the 
basic functions of the memory manager. All the events managed by 
MidiShare are implemented from fixed-sized cells (16 bytes). 
Most of the events need just one cell. Others like the Exclusive
Systems use a variable number of cells linked to one another. 
The user application normally does not have to worry about those 
storage "details". Nevertheless, two functions are provided for 
this low level memory management. The first one, MidiNewCell, 
allows to allocate a simple cell. The second one, MidiFreeCell, 
operates the reverse and de-allocates a cell.


/#Sequence managing

MidiShare offers basic functionalities for the managing of 
sequences  of time ordered events.  The  MidiNewSeq function 
allocates a new sequence, empty at the start. The MidiAddSeq 
procedure inserts an event into a sequence, maintaining the time 
ordered dates. 

The MidiApplySeq procedure is an iterator. It allows to apply a 
procedure to all the events of a sequence. 
The MidiClearSeq procedure frees the content of one sequence and 
the MidiFreeSeq procedure frees the sequence and its content.


/#Real time tasks

The alarm concept is the basis of the MidiShare scheduling mechanism. 
An alarm is a procedure whose address is sent to MidiShare by the 
application. Then, MidiShare will call this procedure in real time 
and often under interruption, to indicate the occurence of an event. 

Each application can define two categories of alarms. The first 
category is defined by the MidiSetApplAlarm procedure. It warns 
of any change in the global context of MidiShare (see paragraph 
"Communications and connections"). The second category is defined
by the MidiSetRcvAlarm procedure. It warns of the presence of new 
events in the reception fifo. This alarm is always called under 
interruption. Therefore, it must not use either directly or 
indirectly the Macintosh Memory Manager. On the reverse, it can have
a free access to all the MidiShare functions (excepted MidiOpen and 
MidiClose), in particular event management. It can also have access 
to global variables of the application, because before the call, 
MidiShare restaures its context register. 

The Macintosh desk accesories cannot have global variables. 
To make up for this drawback, The MidiSetInfo routine allows each 
application to define a data area. This area remains accessible by 
MidiGetInfo function, even during the alarm, and it also serves as 
a global context to desk accessories and other purposes.

Once the RcvAlarm set, the application can easily organise its 
real-time tasks thanks to the private event concept. On the 
reverse of traditional Midi events, private events are meant for 
Midi equipments, but are messages that the application sends to 
itself. The application generally makes use of them to remember 
a task to be done on a precise date.

Therefore, when the date of a private event falls due, MidiShare 
sets the event into the application reception fifo, waiting there 
to be picked up and handled in the same way as Midi events.

MidiShare implements a second mechanism to manage the tasks. This 
is a time-delayed procedure call done thanks to MidiTask (or MidiCall) 
and MidiDTask procedures. To acheive this call, MidiShare collects 
all the call arguments, as well as the routine address to be called
and trigs a special event (TypeProcess or TypeDProcess). When a 
TypeProcess event falls in, MidiShare restaures the application 
context and does proceed to the call. On the reverse, when a 
TypeDProcess event falls in, it is not processed, but set on a 
waiting list belonging to the application. This one will have plenty 
of time to process the waiting tasks when time comes, owing to 
MidiCountDTasks (giving the number of tasks on wait) and 
MidiExec1DTask (processing the next task on wait) functions. 

As the MidiTasks are processed under interruption, they are not 
allowed to call directly or indirectly the operating system. 
The MidiDTasks allow to bypass this obstacle since the application 
trigs their processing (generally in the main loop).

Under certain circumstances, "forgetting" a MidiTask or a 
MidiDTask already launched but not yet processed, can be useful. 
The MidiForgetTask function will be used for that purpose. An 
application  MidiDTask  waiting  list  can  be  deleted  by 
MidiFlushDTasks function. 

At last, in order to make easier communication between the 
application tasks and to manage accesses, shared between 
certain variables, two ininterruptible, pointer-handling 
routines can be used. The MidiReadSync function reads and sets 
to NIL a memory address. The MidiWriteSync function updates an 
address only if NIL. 


/#Midi Time Code Synchronisation

MidiShare can be synchronised to external Midi Time Code (MTC) using 
the MidiSetSyncMode function. 

MidiSetSyncMode takes one parameter describing the choosed 
synchronisation mode (internal or external) and the synchronisation 
input port to be used. The synchronisation mode is global and all Midi 
applications are concerned. The function MidiGetSyncInfo provides 
informations about the synchronisation process. 

When the synchronisation mode is set to internal (the default mode), 
MidiShare is drived by an internal interrupt every millisecond. 
The "size" of the MidiShare time unit is one millisecond. The function 
MidiGetTime gives MidiShare internal time, the time elapsed since the 
very first MidiOpen, expressed in millisecond.

When the synchronisation mode is set to external, MidiShare start 
looking for incomming MTC. When enough MTC are detected, MidiShare 
became locked. It warns all the Midi applications, by calling their 
ApplAlarm, if any, with code MidiSyncStart. A typical sequencer may 
use this information to start playing a sequence according to the 
position of the tape. The function MidiGetExtTime returns the position 
of the tape in milliseconds.

When incomming MTC desappears, MidiShare became unlocked. 
It automatically adjust its time unit to one millisecond and again 
warns the midi applications via their ApplAlarm. with the code 
MidiSyncStop. A typical sequencer application may decide to stop 
playing its sequences.

While MidiShare is locked, it will maintains a constant offset between 
its internal time and the external time (the time of the tape) 
by automatically adjusting  the size of the time unit to follow the 
speed variations of the incomming MTC. The size of the MidiShare time 
unit will be exactly one millisecond when the MTC runs at its nominal 
speed, it will increase when the MTC slow down and decrease when 
the MTC speed up.

For example with a MTC format of 25 frames/second, one frame represents 
40 milliseconds (1000/25). In this case MidiShare will adjust the size 
ofits time unit in order to always have 40 time units per frame whatever 
the actual speed of the incomming MTC is. Consequently, from the point 
of view of a Midi application, the duration of one frame at 
25 frames/seconds will always be 40 milliseconds.

The function MidiGetExtTime returns the external time (the time of the 
tape expressed in milliseconds). While MidiShare is locked :
        MidiGetTime() - MidiGetExtTime() == constant offset
the difference between the MidiShare internal time and the tape time 
expressed in millisecond is a constant. 

Two functions are provided to make conversion between external and 
internal time : MidiInt2ExtTime and MidiExt2IntTime. We have :
        MidiInt2ExtTime( MidiGetTime() ) == MidiGetExtTime()
        MidiExt2IntTime( MidiGetExtTime() ) == MidiGetTime()

Two additional functions, MidiTime2Smpte and MidiSmpte2Time, are 
provided to make conversions between time expressed in millisecond 
and SMPTE locations. 

For example : MidiTime2Smpte( MidiGetExtTime(), 3, &loc ) set loc with 
the current smpte location of the tape using smpte format 3 
(30 frames / seconds).

These functions can be used to convert smpte locations from one format 
to another. For example suppose we want to convert an smpte location 
from its current format to 30 drop frame. we can write :
         MidiTime2Smpte( MidiSmpte2Time (&loc), 2, &loc); 
where 2 means 30 drop frame.



/~REFERENCE
                                                     

/#Midi Event Structure

Typology

The listing below presents the different types of MidiShare 
handled events. This typology contains the whole of the standard 
Midi messages, plus  specific messages such as the TypeNote 
corresponding to a note with its duration ;  The TypeStream 
corresponds to a series of arbitrary bytes, possibly including 
data and status codes, sent directly without any processing; or 
the TypePrivate that are application private messages.

All these codes may be used in the MidiNewEv function to allocate 
an event of the desirable type and are accessible in  an event 
evType field.

Name          Code  Comment 
            
TypeNote       0    pitch, vel and duration (16bits)
TypeKeyOn      1    pitch and vel
TypeKeyOff     2    pitch and vel
TypeKeyPress   3    pitch and press
TypeCtrlChange 4    ctrl and val
TypeProgChange 5    prog
TypeChanPress  6    press
TypePitchWheel 7    Lsb et Msb
            
TypeSongPos    8    Lsb et Msb
TypeSongSel    9    song
TypeClock      10    -
TypeStart      11    -
TypeContinu    12    -
TypeStop       13    -

TypeTune       14    -
TypeActiveSens 15    -
TypeReset      16    -

TypeSysEx      17    data1..dataN
TypeStream     18    byte1..byteN
            
TypePrivate    19..127  arg1, arg2, arg3, arg4
TypeProcess    128      arg1, arg2, arg3, arg4
TypeDProcess   129      arg1, arg2, arg3, arg4
TypeQFrame     130      msg type (0..7) and value

TypeCtrl14b     131
TypeNonRegParam 132
TypeRegParam    133

TypeSeqNum      134  extended types from MidiFile 1.0
TypeText        135
TypeCopyright   136
TypeSeqName     137
TypeInstrName   138
TypeLyric       139
TypeMarker      140
TypeCuePoint    141
TypeChanPrefix  142
TypeEndTrack    143
TypeTempo       144
TypeSMPTEOffset 145

TypeTimeSign    146
TypeKeySign     147
TypeSpecific    148

TypeReserved    149..254
TypeDead        255    -


Internal structure

The MidiShare memory management is organised around fixed-sized 
cells (16 bytes). All the events are composed of a header cell 
that may be followed by one or many extension cells. Figure 1 
describes the different fields composing the basic cell :

The Link field is a multi use link.    
The date field includes the falling in date of the event 
    (from 0 to 231-1).    
The refNum field includes the application reference number 
    sending this.
The evType field indicates the type of the event.    
The Port field indicates the destination Midi port of the event.    
The Chan field indicates the Midi channel of the event. 

These six fields are always present and always have the same meaning,
whatever the type of the event. Their access can be direct. The info 
part contains special fields the meaning of which depends on the type 
of the event. In some cases, Info contain a pointer to one or several
extension cells. Direct access to the special fields is possible 
provided one takes into account the differences of memory storage. 
If not, the special functions MidiGetField and MidiSetField can be 
used. These ones hide the event internal structure and allow to 
have direct access to the special fields by specifying an index 
between 0 and MidiCountFields - 1.

Midi messages with 0, 1 or 2 data bytes, use only one cell. These 
two supplementary fields are accessible by the MidiGetField and 
MidiSetField functions with index 0 and 1.

The notes have three more fields at their disposal : 
0, 1 and 2 for pitch, velocity and duration. The access 
functions MidiGetField and MidiSetField automatically detects 
the 8, 16 or 32 bit fields. 

System Exclusive type messages or Stream type messages include 
variable number of fields. They use a structure build with elementary 
cells linked one to another. The MidiGetField and MidiSetField 
functions are able to follow the links giving access to data. 
The MidiAddField procedure allows the addition of fields at the tail 
of the message.

The private or internal type events need the use of an extension 
cell. This one is composed of four 32 bits fields (from 0 to 3) 
being able to contain any information left to the choice of the 
application.


/#Midi Error Codes
_____________________________________________________________________

List of the error codes returned by some MidiShare functions.

Name    Code    Comment

MIDIerrSpace    -1    No more space available in the freelist or 
                      too many applications 
MIDIerrRefNum   -2    Bad reference number     
MIDIerrBadType  -3    Bad type of event     
MIDIerrIndex    -4    Wrong field index of access to an event 


/#Midi Change Codes
_____________________________________________________________________
List of the change codes sended by MidiShare to ApplAlarm.
When an application need to know about context modifications like 
opening and closing of applications, opening and closing of midi 
ports, changes in connections between applications, it can install an 
ApplAlarm (see MidiSetApplAlarm). This ApplAlarm is then called by 
MidiShare every time a context modification happens with a 32-bits 
code describing the modification. The hi 16-bits part of this code is 
the refNum of the application involved in the context modification, 
the low 16-bits part describe the type of change as listed below.

Name           Code    Comment

MIDIOpenAppl     1    A new application is opened
MIDICloseAppl    2    An application is closed
MIDIChgName      3    The name of an application is changed
MIDIChgConnect   4    A connection is changed 
MIDIOpenModem    5    The Modem port is opened 
MIDICloseModem   6    The Modem Port is closed 
MIDIOpenPrinter  7    The Printer port is opened 
MIDIClosePrinter 8    The Printer Port is closed 

MIDISyncStart    550 Start of synchronization
MIDISyncStop     551 End of synchronization
MIDIChangeSync   552 The synchronization mode is changed



/#MidiAddField
_____________________________________________________________________

Description


Adds a field at the tail of an event of variable length 
(for example a System Exclusive or a Stream) and assigns to it 
the value transmitted as a parameter.


Prototype

C Atari    :  void        MidiAddField (e, v);
C Mac ANSI :  pascal void MidiAddField (MidiEvPtr e, long v);
Pascal Mac :  procedure   MidiAddField (e:MidiEvPtr; v:longint);
Gfa Basic  :  procedure   midi_add_field( e%, v%)


Arguments

e :    a MidiEvPtr, it is a pointer to the event to be modified. 
v :    a 32-bit integer, it is the value of the field to be added. 
    This value is always a long for a purpose of uniformity, but 
    it is internally translate to the right size (a byte in this 
    case). The value of v is actually between 0 and 127 for a System
    Exclusive and between 0 and 255 for a Stream.


_____________________________________________________________________
Example 1 (ANSI C)

Creates the System Exclusive message "F0 67 18 05 F7"

MidiEvPtr    e;

e = MidiNewEv (typeSysEx);
MidiAddField (e, 0x67L);
MidiAddField (e, 0x18L);
MidiAddField (e, 0x05L);


Note : the leading F0 byte and the tailing F7 byte are automaticaly 
added by MidiShare when the message is transmitted. They must not 
be added by the user.


_____________________________________________________________________
Example 2 (ANSI C)

Creates the Stream message "F8 F0 67 F8 18 05 F7" that mix a 
System Exclusive and two MidiClock (F8)

MidiEvPtr    e;
long     i;

e = MidiNewEv(typeStream);
MidiAddField (e, 0xF8L);
MidiAddField (e, 0xF0L);
MidiAddField (e, 0x67L);
MidiAddField (e, 0xF8L);
MidiAddField (e, 0x18L);
MidiAddField (e, 0x05L);
MidiAddField (e, 0xF7L);

Note : Streams are sended without any transformation (no running 
status, no check of coherence). They can be used for example to 
send a long system exclusive split into several chuncks with a 
little delay between. They can also be used as in the example to 
mix real time messages in a long system exclusive for maintaining 
synchronisation.


_____________________________________________________________________
Example 3 (ANSI C)

Create a system exclusive message from an array of values:

char         tab[3] = {10, 20, 30};
MidiEvPtr     aSysEx;

MidiEvPtr Array2SysEx( short len, char* vect, short chan, short port )
{
    MidiEvPtr e;
    
    e = MidiNewEv( typeSysEx );             /* a new, empty sysex   */
    Chan(e) = chan; Port(e) = port;         /* set destination info */
    while (len--) MidiAddField(e, *vect++); /* append fields        */
    return e;
}

aSysEx = Array2SysEx(3, tab, 0, 0);
    

/#MidiAddSeq
_____________________________________________________________________

Description

Inserts an event in a sequence while maintaining the dates in 
time order. 


Prototype

C Atari    : void        MidiAddSeq (s, e);
C Mac ANSI : pascal void MidiAddSeq (MidiSeqPtr s, MidiEvPtr e);
Pascal Mac : procedure   MidiAddSeq (s:MidiSeqPtr; e:MidiEvPtr);
Gfa Basic  : procedure   midi_add_seq( s%, e%)


Arguments

s :    a MidiSeqPtr, it is a pointer on the sequence to be modified. 
e :    a MidiEvPtr, it is a pointer on the event to be added.


_____________________________________________________________________
Example (ANSI C)

Creates a sequence of 10 midi clock every 250 ms.

MidiSeqPtr    s;
MidiEvPtr    e;
long    d;

s = MidiNewSeq();
for (d=0; d< 2500; d+=250) 
{
    e = MidiNewEv (typeClock);
    Date(e) = d;
    MidiAddSeq (s, e);
}


Note : if you are concerned by speed, you must know that 
sequences are single linked lists of time ordered events, 
so it takes more time for MidiAddSeq to insert an event in 
the middle of a sequence that either at the begining or at 
the end.


/#MidiApplySeq
_____________________________________________________________________

Description

This procedure is an iterator. It allows to apply a procedure to 
all the events of a sequence.


Prototype of MidiApplySeq

C Atari    : void        MidiApplySeq (s, MyProc);
C Mac ANSI : pascal void MidiApplySeq (MidiSeqPtr s, ApplyProcPtr p);
Pascal Mac : procedure   MidiApplySeq (s:MidiSeqPtr; p:ApplyProcPtr);
Gfa Basic  : <not implemented>


Arguments of MidiApplySeq

s      : a MidiSeqPtr, it is a pointer to the sequence to be browsed;
MyProc : a ApplyProcPtr is the address of the procedure to apply to 
         each event of the sequence.


Prototype of MyProc

C Atari       : void        MyProc (e);
Turbo C Atari : void cdecl  MyProc (MidiEvPtr e);
C Mac ANSI    : pascal void MyProc (MidiEvPtr e);
Pascal Mac    : procedure   MyProc (e:MidiEvPtr);


Argument of MyProc

e : a MidiEvPtr, it is a pointer to the current event in the sequence.


_____________________________________________________________________
Example (ANSI C)

Transpose a sequence by one octave.

MidiSeqPtr    s;
....

void TransposeOctave (MidiEvPtr e)
{
    if( EvType(e) == typeNote || 
        EvType(e) == typeKeyOn || 
        EvType(e) == typeKeyOff || 
        EvType(e) == typeKeyPress )
        {
            Pitch(e) += 12; /* normally one must check boundaries */
        }
}

MidiApplySeq(s, TransposeOctave);    /* s is a previously created */
                                    /* sequence                  */

Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, all procedure passed as arguments 
of a MidiShare function must be declared as Pascal. In the previous 
exemple, TransposeOctave should be declared as :
pascal void TransposeOctave (MidiEvPtr e)


/#MidiAvailEv
_____________________________________________________________________

Description

Gives a pointer to the first event at the head of the reception fifo, 
without extracting it. MidiAvailEv can be used for very special 
purposes when one wants to test the first event in the reception fifo 
of the application, but without processing it.


Prototype

C Atari    : MidiEvPtr MidiAvailEv (refnum) ;
C Mac ANSI : pascal MidiEvPtr MidiAvailEv (short refnum) ; 
Pascal Mac : Function  MidiAvailEv (refnum: integer) : MidiEvPtr;
Gfa Basic  : Function  midi_avail_ev(refnum&) : MidiEvPtr


Arguments

refNum : a 16-bit integer, it is the reference number of the 
         application.

 
Result

The result is a MidiEvPtr, a pointer to the first event in the 
reception fifo, or NIL if the reception fifo is empty.
 

_____________________________________________________________________
Example (ANSI C)

A function that calculate for how long events have been waiting in 
the reception fifo.

long CalculateWaitTime (short refNum)
{
    MidiEvPtr    e;

    if (e = MidiAvailEv (refNum))
        return MidiGetTime() - Date(e);
    else
        return 0;
}


Note : as the event is still in the reception fifo, it must not be 
destroyed neither sended. It can just be tested or duplicated.


/#MidiCall
_____________________________________________________________________

Description

Defines a time delayed procedure call. When the calling date falls in, 
the call is automatically realized by MidiShare under interruptions. 
MidiCall is presented here for historical reasons, but MidiTask is a 
better choice.


Prototype of MidiCall

C Atari    : void        MidiCall (MyProc, date, refNum, a1, a2, a3);
C Mac ANSI : pascal void MidiCall (TaskPtr MyProc, long date, 
                             short refNum, long a1, long a2, long a3);
Pascal Mac : Procedure   MidiCall (MyProc:TaskPtr; date:longint; 
                                   refNum:integer; a1,a2,a3: longint);
Gfa Basic  : <not implemented>


Arguments of MidiCall

MyProc   : a TaskPtr, it is the address of the procedure to be called.
date     : a 32-bit integer, it is the date at which this call is 
           scheduled. 
refNum   : a 16-bit integer, it is the reference number of the 
           application.
a1,a2,a3 : are 32-bit integers left at the user's disposal, as 
           arguments of MyProc


Prototype of MyProc

C Atari       : void        MyProc (date, refNum, a1, a2, a3);
Turbo C Atari : void cdecl  MyProc (long date, short refNum, 
                                 long a1, long a2, long a3);
C Mac ANSI    : pascal void MyProc (long date, short refNum, 
                                 long a1, long a2, long a3);
Pascal Mac    : procedure   MyProc (date:longint; refNum:integer; 
                                 a1,a2,a3: longint);


Argument of MyProc

date     : a 32-bit integer, it is the date of the call . 
refNum   : a 16-bit integer, it is the reference number of the 
           application.
a1,a2,a3 : are 32-bit integers that can be freely used.


_____________________________________________________________________
Example (ANSI C )

Send periodicaly, every 10 ms, a MidiClock during 30 seconds.

void MyClock(long date, short refNum, long delay, long limit,long a3)
{
    if (date < limit)
    {
        MidiSendIm (refNum, MidiNewEv(typeClock));
        MidiCall (MyClock, date+delay, refNum, delay, limit, a3);
    }
}
...........
long d;
...........
d = MidiGetTime();
MyClock (d, myRefNum, 10L, d+30000L, 0L); /* Start now the clock */
                                         /* for 30s             */

Note : This call being done under interruptions, a few precautions 
should be taken, such as not invoking non-reentrant routines of 
the Operating System (such as the Memory Manager on the Macintosh 
for example). On the contrary, most of the MidiShare functions are 
reentrant, they can be used safely under interrupts.

Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, all procedure passed as arguments 
of a MidiShare function should be declared as Pascal. 
In the previous exemple, MyClock should be declared as :
pascal void MyClock(long date, short refNum, long delay, 
                                     long limit, long a3);


/#MidiClearSeq
_____________________________________________________________________

Description

Frees the content of a sequence. MidiClearSeq de-allocates all 
the events of the given sequence. By consequence this sequence 
becomes empty.


Prototype

C Atari    : void        MidiClearSeq (s);
C Mac ANSI : pascal void MidiClearSeq (MidiSeqPtr s);
Pascal Mac : procedure   MidiClearSeq (s:MidiSeqPtr); 
Gfa Basic  : procedure   midi_clear_seq(s%)


Arguments

s : a MidiSeqPtr, it is a pointer on a sequence whose events are 
    to be freed.


_____________________________________________________________________
Example (ANSI C)

Suppress all but the first event of a sequence.

void ClearAllButFirst (MidiSeqPtr s)
{
    MidiEvPtr e;
    
    if (s && First(s))             /* Check a non empty sequence */
    {
        e = MidiCopyEv(First(s));  /* make a safe copy of the    */
                                   /* first event                */
        MidiClearSeq(s);           /* clear the content of the   */
                                   /* sequence                   */
        MidiAddSeq(s, e);          /* add the event to the empty */
                                   /* sequence                   */
    }
}
        

Note : a sequence consist of a header of 4 pointers. The first one 
points to the first event of the sequence. The second one points 
to the last event. The other two pointers are reserved for future 
extensions and must be NIL. In an empty sequence, the pointers to 
the first and last events are NIL.


/#MidiClose
_____________________________________________________________________

Description

Closing of a MidiShare application. Every opening of MidiShare with 
MidiOpen must be counter-balanced by a call to MidiClose, so that 
MidiShare keeps the exact account of active applications and released 
the corresponding internal data structures. All the MidiShare 
applications owning a "context alarm" will be informed of 
this closing.


Prototype

C Atari    : void        MidiClose (refNum);
C Mac ANSI : pascal void MidiClose (short refNum);
Pascal Mac : procedure   MidiClose (refNum:integer);
Gfa Basic  : procedure   midi_close(refNum&)


Arguments

refNum : a 16-bit integer, it is the reference number of the 
         application, given by the corresponding MidiOpen.


_____________________________________________________________________
Example (ANSI C)

A DoNothing MidiShare application.

#include MidiShare.h
#include <stdio.h>

short    myRefNum;

main()
{
    if ( ! MidiShare() )     exit(1);    /* Check MidiShare loaded */
    myRefNum = MidiOpen("Sample");       /* Ask for a ref. number  */
    if ( myRefNum < 1 )     exit(1);     /* Check MidiOpen success */
    printf( "refNum : %i \n", myRefNum); /* Print the ref. number  */
    MidiClose(myRefNum);                 /* And close              */
}

Note : MidiClose take care of deleting all the connections with the 
concerned application. Therefore if an application sends some Midi 
events and without delay, does a MidiClose, these sended events will 
probably not be actually transmitted. They just go back to the 
MidiShare Memory Manager.

Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, all strings passed as arguments 
of a MidiShare function must be Pascal strings. In the previous 
exemple, one must write :         
myRefNum = MidiOpen("\pSample");


/#MidiConnect
_____________________________________________________________________

Description

Connects or disconnects two applications. The MidiConnect procedure 
allows to switch on or off a connection between a source application 
and a destination application. There is no restrictions to the 
establishing of connections, an application can be source or 
destination as many times as you wish. Loops are permitted.


Prototype

C Atari   : void        MidiConnect (src, dest, state);
C Mac ANSI: pascal void MidiConnect (short src, short dest, 
                                              boolean state);
Pascal Mac: Procedure   MidiConnect (src, dest:integer; state:boolean);
Gfa Basic : Procedure   midi_connect(src&,dest&,state!)


Arguments

src   : a 16-bit integer, it is the reference number of the source 
        application. 
dest  : a 16-bit integer, it is the reference number of the 
        destination application.
state : a boolean, it indicates if a connection must be switched on 
        (True) or off (False).


_____________________________________________________________________
Example (ANSI C)

Open a MidiShare application and connect it to the physical Midi 
inputs and outputs.

#include MidiShare.h
#define PHYSMIDI_IO 0    /* The MidiShare physical Midi I/O ports*/

Main()
{
    short    myRefNum;

    myRefNum = MidiOpen("MidiSample");

    MidiConnect(PHYSMIDI_IO, myRefNum, TRUE); /* to receive events */
    MidiConnect(myRefNum, PHYSMIDI_IO, TRUE); /* to transmit events*/

    /* ....... */

    MidiClose(myRefNum);
}

Note : the physical Midi inputs and outputs are represented by the 
pseudo application called "MidiShare" with a reference number of 0 
(zero). This pseudo application is automaticaly created when 
MidiShare wakes up at the very first MidiOpen.


/#MidiCopyEv
_____________________________________________________________________

Description

Duplicates an event. MidiCopyEv takes into account the structure of 
the event. It can be used to copy every type of events, from simple 
notes to big system exclusives.


Prototype

C Atari    : MidiEvPtr        MidiCopyEv (e);
C Mac ANSI : pascal MidiEvPtr MidiCopyEv (MidiEvPtr e);
Pascal Mac : Function         MidiCopyEv (e: MidiEvPtr): MidiEvPtr;
Gfa Basic  : Function         midi_copy_ev(e%) : MidiEvPtr


Arguments

e :     a MidiEvPtr, it is a pointer to the event to be copied.


Result

The result is a MidiEvPtr, a pointer to the copy if the operation 
was sucessfull. The result is NIL if MidiShare was not able to 
allocate enough memory space for the copy.


_____________________________________________________________________
Example (ANSI C)

Send from now, 10 times an identical note of pitch 60 every 250 ms.

MidiEvPtr    e;
short        myRefNum;
long         d;
short        i;
........

e = MidiNewEv (typeNote);    /* create template note      */
Pitch(e)= 60;                /* fill up its parameters    */
Vel(e)  = 80;
Dur(e)  = 250;
Chan(e) = 0;
Port(e) = 0;

for (d=MidiGetTime(), i=0; i<10; i++, d+=250) /* send the 10 copies*/
    MidiSendAt (myRefNum, MidiCopyEv(e), d);  /*   of the template */

MidiFreeEv(e);                            /* and free the template */



Note : it is very important to note that, once an event is sended, it 
must never be used any more by the application. Consequently, if one 
need to send several times the same midi message, one must send 
different copies.


/#MidiCountAppls
_____________________________________________________________________

Description
Gives the number of Midi applications on activity. 

Prototype
C Atari    : short        MidiCountAppls();
C Mac ANSI : pascal short MidiCountAppls();
Pascal Mac : Function     MidiCountAppls : integer;
Gfa Basic  : Function     midi_count_appls : integer

Result

The result is a 16-bit integer, the number of currently opened Midi 
applications.


_____________________________________________________________________
Example (ANSI C)

Print the name of all the actives MidiShare applications

void PrintApplNames(void)
{
    short     ref;
    short     i;
    
    printf( "List of MidiShare applications :\n" );
    for( i = 1; i <= MidiCountAppls(); ++i )
    {
        ref = MidiGetIndAppl(i);
        printf("%i : %s \n", ref, MidiGetName( ref ) );
    }
}


Note for Mac users : MidiShare was originaly developed for Pascal 
on the Macintosh. Consequently, in C, the result of MidiGetName is 
a Pascal string that must be converted to a C string before being 
printed.


/#MidiCountDTasks
_____________________________________________________________________

Description

Returns the number of time delayed tasks waiting in the list of the 
application. Delayed tasks are function calls that where scheduled 
with MidiDTask and that are now ready to be executed in the 
DTasksFifo of the application.


Prototype

C Atari    : long        MidiCountDTasks (refNum);
C Mac ANSI : pascal long MidiCountDTasks (short refNum);
Pascal Mac : Function    MidiCountDTasks (refNum: integer): longint;
Gfa Basic  : <not implemented>


Arguments

refNum : a 16-bit integer, the reference number of the application.


Result

The result is a 32-bit integer, the number of waiting DTasks.


_____________________________________________________________________
Example (ANSI C)

Execute the waiting DTasks of a MidiShare application.

void ExecuteAllDTasks(short refNum)
{
    long    n;

    for (n=MidiCountDTasks(refNum), n>0; n--)
    {
        MidiExec1DTask(refNum);
    }
}


Note : This is what a typical application must do, generaly in its  
main event loop, to actually execute previously scheduled 
MidiDTasks. Since these MidiDTasks are executed in the main event 
loop, they can do Operating System call without trouble. In return, 
as MidiDTasks are not executed under interrupts, they are not as 
accurate in time as MidiTasks.


/#MidiCountEvs
_____________________________________________________________________

Description

Gives the number of events on wait into the reception fifo of the 
application.


Prototype

C Atari    : long        MidiCountEvs (refnum);
C Mac ANSI : pascal long MidiCountEvs (short refnum);
Pascal Mac : Function    MidiCountEvs (refnum: integer) : longint;
Gfa Basic  : Function    midi_count_evs(refnum&) : longint


Arguments

refNum : a 16-bit integer, the reference number of the application.


Result

The result is a 32-bit integer, the number of waiting events in the 
reception fifo.


_____________________________________________________________________
Example (ANSI C)

A receive alarm that processes all the received events by adding to 
their date a one second delay.

void OneSecDelay (short refNum)
{
    MidiEvPtr    e;
    long n;

    for ( n = MidiCountEvs(refNum); n > 0; --n ) 
    {                                
        e = MidiGetEv(refNum);  /* Get an event from the fifo    */
        Date(e) += 1000;        /* Add 1000 ms to its date       */
        MidiSend(refNum,e);     /* Then send the event           */
    }
}

......

MidiSetRcvAlarm(myRefNum,OneSecDelay);  /* Activate the receive */
                                        /* alarm                */


Note : such a procedure can be called repeatedly in the main event 
loop of the application, but for really accurate time control, it 
must be installed as a receive alarm with MidiSetRcvAlarm.

Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, all procedure passed as arguments 
of a MidiShare function must be declared as Pascal. In the previous 
exemple, OneSecDelay must be declared as :     
pascal void OneSecDelay (short refNum)


/#MidiCountFields
_____________________________________________________________________

Description

Gives the number of fields of an event. 


Prototype

C Atari    : long        MidiCountFields (e);
C Mac ANSI : pascal long MidiCountFields (MidiEvPtr e);
Pascal Mac : Function     MidiCountFields (e: MidiEvPtr): longint;
Gfa Basic  : Function     midi_count_fields(e%) : longint


Arguments

e :     a MidiEvPtr, a pointer to the concerned event.


Result

The result is a 32-bit integer, the number of fields of the event.


_____________________________________________________________________
Example (ANSI C)

An universal method for printing of a MidiShare event.

void PrintEv(MidiEvPtr e)
{
    long i, n;
    
    n = MidiCountFields(e);
    printf( "Event %x content :\n", e );
    printf( " link : %x\n", Link(e) );
    printf( " date : %i\n", Date(e) );
    printf( " type : %i\n", EvType(e) );
    printf( "  ref : %i\n", RefNum(e) );
    printf( " port : %i\n", Port(e) );
    printf( " chan : %i\n", Chan(e) );
    printf( " %i fields : ( ", n );
    for(i=0; i<n; ++i) printf("%i ",MidiGetField(e,i) );
    printf( ")\n" );
}

Note : MidiShare events carry two kind of information : 
common information, like date, type, channel, port ..., 
and specific information that depend of the type of event. 
Fields allow a uniform way to access these specific information. 
Some events have fixed number of fields (for exemple notes have 
three fields : pitch (8-bit), velocity (8-bit) and duration (16-bit)). 
Some other, like system exclusive have a variable number of fields.


/#MidiDTask
_____________________________________________________________________

Description

On the same way as MidiTask, MidiDTask allows to realize a time 
delayed procedure call ; but on the reverse to MidiTask, the call is 
not achieved under interruption as soon as falling time is due. 
The address of the routine to be executed and the corresponding 
arguments will be stored into a special list. The application will 
be allowed to process these on-wait tasks, one by one, thanks to 
MidiExec1DTask.


Prototype of MidiDTask

C Atari    : MidiEvPtr MidiDTask (MyProc, date, refNum, 
                                                      a1, a2, a3);
C Mac ANSI : pascal MidiEvPtr MidiDTask (ProcPtr MyProc, long date, 
                             short refNum, long a1, long a2, long a3);
Pascal Mac : Function MidiDTask (MyProc:ProcPtr; date:longint; 
                    refNum:integer; a1,a2,a3: longint):MidiEvPtr;
Gfa Basic  : <not implemented>


Arguments of MidiDTask

MyProc   : is the address of the procedure to be called.
date     : a 32-bit integer, it is the date at which this call 
           is scheduled. 
refNum   : a 16-bit integer, it is the reference number of the 
           application.
a1,a2,a3 : are 32-bit integers left at the user's disposal, as 
           arguments to MyProc


Result of MidiDTask

The result, a MidiEvPtr, is a pointer to a typeDProcess MidiShare 
event. The result is NIL if MidiShare runs out of memory.


Prototype of MyProc

C Atari       :    void        MyProc (date, refNum, a1, a2, a3);
Turbo C Atari :    void cdecl  MyProc (long date, short refNum, 
                                    long a1, long a2, long a3);
C Mac ANSI    :    pascal void MyProc (long date, short refNum, 
                                    long a1, long a2, long a3);
Pascal Mac    :    procedure   MyProc (date:longint; refNum:integer; 
                                    a1,a2,a3: longint);


Argument of MyProc

date     : a 32-bit integer, it is the date of the call . 
refNum   : a 16-bit integer, it is the reference number of the 
           application.
a1,a2,a3 : are 32-bit integers that can be freely used.


_____________________________________________________________________
Example (ANSI C)

Schedule Action() procedure call 1000 ms ahead.

MidiEvPtr    myDTask;

MyDTask = MidiDTask(Action,MidiGetTime()+1000,myRefNum, a1, a2, a3);

Note : The result, in myDTask, can be used to test the success of 
MidiDTask. It can also be used by MidiForgetTask to try to "forget"
a scheduled task before it happens.


/#MidiExec1DTask
_____________________________________________________________________

Description

Processes the first time delayed task on wait in the application list. 
The time delayed tasks scheduled by MidiDTask are not processed as 
soon as time falls in, but stored into a special list proper to each 
application, so they can be processed out of interruption.


Prototype

C Atari    : void        MidiExec1DTask (refnum);
C Mac ANSI : pascal void MidiExec1DTask (short refnum);
Pascal Mac : procedure   MidiExec1DTask (refnum: integer);
Gfa Basic  : <not implemented>


Arguments

refNum     : a 16-bit integer, it is the reference number of the 
          application.


_____________________________________________________________________
Example (ANSI C)

Execute the waiting DTasks of a MidiShare application.

void ExecuteAllDTasks(short refNum)
{
    long    n;

    for (n=MidiCountDTasks(refNum), n>0; n--)
    {
        MidiExec1DTask(refNum);
    }
}


Note : This is what a typical application must do, generaly in its 
main event loop, to actually execute previously scheduled MidiDTasks.
Since these MidiDTasks are executed in the main event loop, they can 
do Operating System Call without trouble. In return, as MidiDTasks 
are not executed under interrupts, they are not as accurate in time 
as MidiTasks.


/#MidiExt2IntTime
_____________________________________________________________________

Description

Convert an external time in millisecond to an internaltime. 
The convertion is made by substractiong the current offset between 
internal and external time.

Prototypes
C Atari    :    long         MidiExt2IntTime(time);
C Mac ANSI :    pascal long  MidiExt2IntTime(long time);
Pascal Mac :    Function     MidiExt2IntTime(time : longint): longint;
Gfa Basic  :    Function     midi_ext_2_int_time(time%) : longint


Arguments

time : a 32-bits time in milliseconds


Result

the corresponding internal time, a 32-bits value in milliseconds.


Note :
When MidiShare is locked we have the following equivalence :
    MidiExt2IntTime( MidiGetExtTime() ) == MidiGetTime()
We have also :
    TSyncInfo myInfo;
    MidiGetSyncInfo(&myInfo);
    MidiExt2IntTime(x) == x - myInfo.syncOffset


/#MidiFlushDTasks
_____________________________________________________________________

Description

Flushes all the waiting DTasks in the application DTask list.


Prototype

C Atari    : void        MidiFlushDTasks (refnum);
C Mac ANSI : pascal void MidiFlushDTasks (short refnum);
Pascal Mac : procedure   MidiFlushDTasks (refnum: integer);
Gfa Basic  : <not imlemented>


Arguments

refNum : a 16-bit integer, it is the reference number of the 
         application.


_____________________________________________________________________
Example (ANSI C)

Flushes all the waiting DTasks in the application DTask list.

short    myRefNum;

.....

MidiFlushDTasks (myRefNum);


/#MidiFlushEvs
_____________________________________________________________________

Description

Flushes all the waiting events in the reception fifo of the 
application.


Prototype

C Atari    : void        MidiFlushEvs( refNum );
C Mac ANSI : pascal void MidiFlushEvs( short refNum );
Pascal Mac : procedure   MidiFlushEvs( refNum : integer );
Gfa Basic  :
HyperCard  :


Arguments

refNum     : a 16-bit integer, it is the reference number of the 
          application.


_____________________________________________________________________
Example (ANSI C)

Flushes all the waiting events in the application reception fifo.

short    myRefNum;

.....

MidiFlushEvs (myRefNum);


/#MidiForgetTask
_____________________________________________________________________

Description

Tries to "forget" a previously scheduled Task or DTasks. This a very 
powerfull, but dangerous function. One must be shure that the task 
is not yet executed before calling MidiForgetTask.


Prototype

C Atari    : void        MidiForgetTask (v);
C Mac ANSI : pascal void MidiForgetTask (MidiEvPtr *v);
Pascal Mac : procedure   MidiForgetTask (var v: MidiEvPtr);
Gfa Basic  : <not implemented>


Arguments

v : is the address of a variable pointing to a previously 
    scheduled Task or DTask but not yet executed. The variable
    may also contain NIL. In this case MidiForgetTask does nothing.

Side effect

The variable, wich address is given in parameter, is set to NIL by 
MidiForgetTask.


_____________________________________________________________________
Example 1 (ANSI C)

Create an infinit periodic clock (every 250ms) and stop it with 
MidiForgetTask.

MidiEvPtr   theClock;

void InfClock (long date, short refNum, long delay, long a2, long a3)
{
    MidiSendIm (refNum, MidiNewEv(typeClock));
    theClock = MidiTask (InfClock, date+delay, refNum, delay, a2, a3);
}

InfClock(MidiGetTime(), myRefNum, 250L, 0L, 0L); /* Start the clock */
.........                                        /* Wait some time  */
MidiForgetTask(&theClock);                       /* And forget it   */


_____________________________________________________________________
Example 2 (ANSI C)

In the previous example, theClock always point to a valid task because
InfClock never stop by itself. If the task may decide to stop itself,
it must set the pointer to NIL in order to avoid to forget an invalid
task.

MidiEvPtr    theClock;

void CountClock (long date, short refNum, long delay, long count, long a3)
{
   if( count > 0)
   {
      MidiSendIm (refNum, MidiNewEv(typeClock));
      theClock = MidiTask (CountClock, date+delay, refNum, delay, count-1, a3);
   } else {
      theClock = nil;     /* here the task decide to stop itself */
                          /* so set the pointer to nil           */
   }

InfClock(MidiGetTime(), myRefNum, 250L, 100L, 0L); /* Start the clock  */
.........                                          /* Wait some time   */
MidiForgetTask(&theClock);                         /* And forget it    */

If MidiForgetTask happens before the end of the 100 clocks, theClock point
to a valid task and MidiForgetTask(&theClock) is safe. If MidiForgetTask 
happens after the end of the 100 clocks, theClock contains NIL and 
MidiForgetTask(&theClock) is safe and will do nothing.


/#MidiFreeCell
_____________________________________________________________________

Description

Frees a cell allocated by MidiNewCell function. This is the lowest 
level for accessing the MidiShare Memory Manager. One must be shure 
to use MidiFreeCell on an individual cell allocated with MidiNewCell 
and not on complet MidiShare events. Not doing so may result on 
losting cells.


Prototype

C Atari    : void        MidiFreeCell (c);
C Mac ANSI : pascal void MidiFreeCell (MidiEvPtr c);
Pascal Mac : procedure   MidiFreeCell (c: MidiEvPtr);
Gfa Basic  : procedure   midi_free_cell(c%)


Arguments

c :     a MidiEvPtr, a pointer to a basic cell of 16 bytes.


_____________________________________________________________________
Example (ANSI C)

Free a cell previously allocated.

MidiEvPtr    aCell;

aCell = MidiNewCell();

....

MidiFreeCell( aCell );

Note : Cells allocated with MidiNewCell must be freed with 
MidiFreeCell and not with MidiFreeEv.


/#MidiFreeEv
_____________________________________________________________________

Description

Frees a MidiShare event allocated with MidiNewEv. MidiFreeEv takes 
into account the event structure by checking the event type. For 
this reason, MidiFreeEv must not be used on cell allocated with 
MidiNewCell. 


Prototype

C Atari    : void        MidiFreeEv (e);
C Mac ANSI : pascal void MidiFreeEv (MidiEvPtr e);
Pascal Mac : procedure   MidiFreeEv (e: MidiEvPtr);
Gfa Basic  : procedure   midi_free_ev(e%)


Arguments

e :     a MidiEvPtr, it is a pointer to a MidiShare event.

_____________________________________________________________________
Example (ANSI C)


A receive alarm that delete all the received events.

short    myRefNum;
.....

void DeleteAll( short refNum )
{
    MidiEvPtr    e;
    long n;

    for ( n = MidiCountEvs(refNum); n > 0; --n ) 
    {                                
        e = MidiGetEv( refNum );    /* Get an event from the fifo */
        MidiFreeEv( e );            /* Then free it               */
    }
}
......

MidiSetRcvAlarm( myRefNum, DeleteAll ); /* Activate receive alarm */


Note : Obviously it is more simple and fast to use MidiFlushEvs to 
achieve the same result.

Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, all procedure passed as arguments 
of a MidiShare function must be declared as Pascal. In the previous 
exemple, DeleteAll must be declared as :         
pascal void DeleteAll( short refNum )


/#MidiFreeSeq
_____________________________________________________________________

Description

Frees a sequence and its content. MidiFreeSeq first de-allocates all 
the events of the given sequence and then the sequence header itself.


Prototype

C Atari    : void        MidiFreeSeq (s);
C Mac ANSI : pascal void MidiFreeSeq (MidiSeqPtr s);
Pascal Mac : procedure   MidiFreeSeq (s:MidiSeqPtr); 
Gfa Basic  : procedure   midi_free_seq(s%)


Arguments

s :    a MidiSeqPtr, it is a pointer on a sequence to be freed.


_____________________________________________________________________
Example (ANSI C)

Frees a previously allocated sequence s.

MidiSeqPtr    s;

s = MidiNewSeq();
....
MidiFreeSeq(s);

Note : Once freed, s is no more a valid pointer.


/#MidiFreeSpace
_____________________________________________________________________

Description

Gives the available space. MidiFreeSpace allows to know at any time 
the number of cells remaining available from the MidiShare memory 
manager.  


Prototype

C Atari    : long        MidiFreeSpace();
C Mac ANSI : pascal long MidiFreeSpace(void);
Pascal Mac : Function    MidiFreeSpace : longint;
Gfa Basic  : Function    midi_free_space : longint


Arguments

none


Result

The result is a 32-bit integer, the number of available free 
cells in the MidiShare memory manager.


_____________________________________________________________________
Example (ANSI C)

Print informations about MidiShare memory space.

void PrintMemInfo(void)
{
 printf("MidiShare memory :\n");
 printf("free space  : %i cells\n", MidiFreeSpace());
 printf("used space  : %i cells\n", MidiTotalSpace()-MidiFreeSpace());
 printf("total space : %i cells\n", MidiTotalSpace());
}


Note : MidiFreeSpace inhibits all interrupts during its execution. 
If the remaining space is very large MidiFreeSpace can take a long 
time to execute and may cause overrun errors with fast incoming 
Midi data.


/#MidiGetApplAlarm
_____________________________________________________________________

Description

Gives the context alarm of an application. MidiGetAlarm allows to 
know the address of the context alarm procedure associated to the 
application. This alarm is automatically called by MidiShare to 
inform the application of all the changes happened into the active 
Midi applications (name or connection changes, closing, opening, etc.)


Prototype of MidiGetApplAlarm

C Atari    : ApplAlarmPtr        MidiGetApplAlarm(refNum);
C Mac ANSI : pascal ApplAlarmPtr MidiGetApplAlarm(short refNum);
Pascal Mac : Function MidiGetApplAlarm(refNum: integer): ApplAlarmPtr;
Gfa Basic  : <not implemented>


Arguments of MidiGetApplAlarm

refNum : a 16-bit integer, it is the reference number of the 
         application.


Result

the result, a ApplAlarmPtr, is the address of the alarm routine or NIL 
if no such routine where installed.


Prototype of an ApplAlarm routine

C Atari    : void        MyApplAlarm (refNum, code);
C Mac ANSI : pascal void MyApplAlarm (short refNum, long code);
Pascal Mac : procedure   MyApplAlarm (refNum:integer;code:longint);


Argument of an ApplAlarm routine

refNum : a 16-bit integer, it is the reference number of the 
          application.
code   : a 32-bit integer, the context modification code. 


_____________________________________________________________________
Example (ANSI C)

Disable temporarily the application context alarm.

ApplAlarmPtr p;
.....
p = MidiGetApplAlarm( myRefNum );
MidiSetApplAlarm( NIL );    /* Disable application context alarm  */
.....
MidiSetApplAlarm( p );      /* Restaure application context alarm */


/#MidiGetEv
_____________________________________________________________________

Description

Extracts the event on top of the reception fifo. The received events, 
stored automaticaly by MidiShare in the application reception fifo, 
can be picked up by successive calls to MidiGetEv function.


Prototype

C Atari    : MidiEvPtr        MidiGetEv (refNum) ;
C Mac ANSI : pascal MidiEvPtr MidiGetEv (short refNum) ; 
Pascal Mac : Function    MidiGetEv (refNum: integer) : MidiEvPtr;
Gfa Basic  : Function    midi_get_ev(refNum&) : MidiEvPtr


Arguments

refNum : a 16-bit integer, it is the reference number of the 
         application.
 

Result

a MidiEvPtr, a pointer to the first event in the reception Fifo, 
or NIL if the fifo is empty. The event is extracted form the 
reception fifo.

_____________________________________________________________________
Example (ANSI C)

A receive alarm that processes all the received events by adding to 
their date a one second delay.

void OneSecDelay (short refNum)
{
    MidiEvPtr    e;
    long n;

    for ( n = MidiCountEvs(refNum); n > 0; --n ) 
    {                                
        e = MidiGetEv(refNum);  /* Get an event from the fifo    */
        Date(e) += 1000;        /* Add 1000 ms to its date       */
        MidiSend(refNum,e);     /* Then send the event           */
    }
}

......

MidiSetRcvAlarm(myRefNum,OneSecDelay);/* Activate the receive alarm*/


Note : such a procedure can be called repeatedly in the main event 
loop of the application, but for really accurate time control, it 
must be installed as a receive alarm with MidiSetRcvAlarm.

Note for Mac users : MidiShare was originaly developed for Pascal 
on the Macintosh. Consequently, in C, all procedure passed as 
arguments of a MidiShare function must be declared as Pascal. In 
the previous exemple, OneSecDelay must be declared as :     
pascal void OneSecDelay (short refNum)


/#MidiGetExtTime
_____________________________________________________________________

Description

Return the current external time, the position of the tape converted 
in milliseconds.


Prototypes

C Atari    : long         MidiGetExtTime();
C Mac ANSI : pascal long  MidiGetExtTime (void);
Pascal Mac : Function     MidiGetExtTime : longint;
Gfa Basic  : Function midi_get_ext_time(void) : longint


Arguments

none


_____________________________________________________________________
Example (ANSI C)

Gives the SMPTE current location of the tape.

  TSyncInfo      myInfo;
  TSmpteLocation myLoc;

  MidiGetSyncInfo(&myInfo);
  MidiTime2Smpte( MidiGetExtTime(), myInfo.syncFormat, &myLoc);


Note: when the tape is stopped, MidiGetExtTime returns the stop 
position of the tape converted in milliseconds.


/#MidiGetField
_____________________________________________________________________

Description

Return the i index field value of an event. Field index start from 0. 
Depending of the event type and field nature, the field format can 
be 8, 16 or 32-bit. MidiGetField deals with all the format conversion
and the result is always a 32-bit integer.


Prototype

C Atari    : long           MidiGetField (e, f);
C Mac ANSI : pascal long    MidiGetField (MidiEvPtr e, long f);
Pascal Mac : Function MidiGetField(e: MidiEvPtr; f: longint):longint;
Gfa Basic  : Function midi_get_field(e%,f%)


Arguments

e :    a MidiEvPtr, it is a pointer on the event to be acces. 
f :    a 32-bit integer, it is the field number to be read 
    (numbered from 0).


Result

The result is a 32-bit integer, the value of the field. Fields are 
considered as unsigned. 


_____________________________________________________________________
Example (ANSI C)

An universal method for printing of a MidiShare event.

void PrintEv(MidiEvPtr e)
{
    long i, n;
    
    n = MidiCountFields(e);
    printf( "Event %x content :\n", e );
    printf( " link : %x\n", Link(e) );
    printf( " date : %i\n", Date(e) );
    printf( " type : %i\n", EvType(e) );
    printf( "  ref : %i\n", RefNum(e) );
    printf( " port : %i\n", Port(e) );
    printf( " chan : %i\n", Chan(e) );
    printf( " %i fields : ( ", n );
    for(i=0; i<n; ++i) printf("%ld ",MidiGetField(e,i) );
    printf( ")\n" );
}

Note : MidiShare events carry two kind of information : 
common information, like date, type, channel, port ..., and 
specific information that depend of the type of event. Fields 
allow a uniform way to acces these specific information. Some 
events have fixed number of fields (for example notes have three 
fields : pitch (8-bit), velocity (8-bit) and duration (16-bit)). 
Some other, like system exclusive have a variable number of fields.


/#MidiGetFilter
_____________________________________________________________________

Description

Gives the associated filter of an application. Each application can 
select the events to be received by using a filter. The filtering 
processus is local to the application and has no influence on the 
events received by other applications. 


Prototype

C Atari    : FilterPtr        MidiGetFilter (refNum);
C Mac ANSI : pascal FilterPtr MidiGetFilter (short refNum);
Pascal Mac : Function MidiGetFilter (refNum: integer): FilterPtr;
Gfa Basic  : Function midi_get_filter(refNum&) : FilterPtr


Arguments

refNum :     a 16-bit integer, the reference number of the application


Result

the result is a FilterPtr, a pointer to the filter associated to the 
application, or NIL if there is no such filter (in this case the 
application accepts any events)


_____________________________________________________________________
Example (ANSI C)
                    << to be supplied >>


/#MidiGetIndAppl
_____________________________________________________________________

Description
Gives the reference of number of an application from is order number. 
The MidiGetIndAppl function allows to know the reference number of 
any application by giving its order number (a number between 1 and 
MidiCountAppls() ).


Prototype
C Atari    : short        MidiGetIndAppl (index);
C Mac ANSI : pascal short MidiGetIndAppl (short index);
Pascal Mac : Function MidiGetIndAppl (index: integer) : integer;
Gfa Basic  : Function midi_get_ind_appl(index&) : integer

Arguments
index :     a 16-bit integer, it is the index number of an application 
between 1 and MidiCountAppls().

Result
The result is an application reference number or MIDIerrIndex if the 
index is out of range.

_____________________________________________________________________
Example (ANSI C)

Print the name of all the actives MidiShare applications

void PrintApplNames(void)
{
    short     ref;
    short     i;
    
    printf( "List of MidiShare applications :\n" );
    for( i = 1; i <= MidiCountAppls(); ++i )
    {
        ref = MidiGetIndAppl(i);
        printf("%i : %s \n", ref, MidiGetName( ref ) );
    }
}


Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, the result of MidiGetName is a 
Pascal string that must be converted to a C string before being 
printed.


/#MidiGetInfo
_____________________________________________________________________

Description
Gives the content of a 32-bit field an application can use for 
any purpose. This field remains accessible by MidiGetInfo during 
alarms and interrupts. It can be used as a global context if 
necessary (for example for desk accessories on the Macintosh)



Prototype
C Atari    : Ptr          MidiGetInfo( short refNum );
C Mac ANSI : pascal void *MidiGetInfo( short refNum );
Pascal Mac : Function     MidiGetInfo( refNum: integer ) : Ptr;
Gfa Basic  : Function     mdi_get_info(refNum&) : Ptr

Arguments
refNum : a 16-bit integer, the reference number of the application

Result : a 32 bits integer : the last value set by MidiSetInfo.


_____________________________________________________________________
Example (ANSI C)
                    << to be supplied >>


/#MidiGetName
_____________________________________________________________________

Description

Gives the name of an application. Knowing an application reference 
number, it is possible to find its name using the MidiGetName 
function. On the reverse, it is also possible to find the reference 
number of an application via its name using the MidiGetNamedAppl 
function.


Prototype

C Atari    : MidiName        MidiGetName(refNum);
C Mac ANSI : pascal MidiName MidiGetName(short refNum);
Pascal Mac : Function MidiGetName (refNum: integer) : MidiName;
Gfa Basic  : Function midi_get_name(efNum&) : MidiName


Arguments

refNum : a 16-bit integer, the reference number of the application


Result

The result is pointer on a character string representing the 
application name.


_____________________________________________________________________
Example (ANSI C)

Print the name of all the active MidiShare applications

void PrintApplNames(void)
{
    short     ref;
    short     i;
    
    printf( "List of MidiShare applications :\n" );
    for( i = 1; i <= MidiCountAppls(); ++i )
    {
        ref = MidiGetIndAppl(i);
        printf("%i : %s \n", ref, MidiGetName( ref ) );
    }
}


Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, the result of MidiGetName is a 
Pascal string that must be converted to a C string before being 
printed.


/#MidiGetNamedAppl
_____________________________________________________________________

Description

Gives the reference number of an application. Knowing an application 
name, it is possible to find its reference number using the 
MidiGetNamedAppl function. On the reverse, it is also possible to 
find the name of an application via its reference number using the 
MidiGetName function.


Prototype

C Atari    : short        MidiGetNamedAppl (MidiName name);
C Mac ANSI : pascal short MidiGetNamedAppl (MidiName name);
Pascal Mac : Function MidiGetNamedAppl (name: MidiName) : integer;
Gfa Basic  : Function midi_get_named_appl(name$) : integer


Arguments

name :     the application name.


Result

The result is the reference number of the application.


_____________________________________________________________________
Example (ANSI C)

Find the reference number of the "MidiShare" pseudo-application.

short    r;

r = MidiGetNamedAppl("MidiShare");/* MidiShare reference is always 0*/


Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, all stings passed as arguments of 
a MidiShare function must be Pascal strings. In the previous example, 
one must write :        
MidiGetNamedAppl("\pMidiShare")


/#MidiGetPortState
_____________________________________________________________________

Description

Gives the Midi port state. The switching on or off of Midi ports is 
controlled by the MidiSetPortState and MidiGetPortState routines. 
These must be used with care since they affect all the applications.


Prototype

C Atari    : Boolean        MidiGetPortState(port);
C Mac ANSI : pascal Boolean MidiGetPortState(short port);
Pascal Mac : Function MidiGetPortState(port: integer): boolean;
Gfa Basic  : Function midi_get_port_state(port&) : boolean


Arguments

port :     a port number from 0 to 255.


Result

The result is true if the port is open or false if the port is closed.


_____________________________________________________________________
Example (ANSI C)

Print the state of all the Midi ports.

void PrintPortsState(void)
{
    short i;
    
    printf( "Midi ports state :\n");
    for( i = 0; i < 256; ++i )
    {
        if ( MidiGetPortState( i ) )
            printf(" %i is open \n", i );
        else
            printf(" %i is closed \n", i );
    }
}


Note : On the Atari, there is just one Midi port (port 0), and on 
the Macintosh there are just two ports (port modem: 0, 
port printer: 1). But the future Lan version of MidiShare will allow 
up to 256 ports to be used. Therefore, applications must consider 
that 256 ports are available.


/#MidiGetRcvAlarm
_____________________________________________________________________

Description

Gives the address of reception alarm of an application.The reception 
alarm warns of the presence of new events in the reception fifo. 
This alarm is always called under interruption. Therefore, it must 
not make use, either directly or indirectly, the Macintosh Memory
Manager. On the reverse, it can have a free access to all the 
MidiShare functions (exept MidiOpen and MidiClose), in particular 
event management. It can also use global variables of the application, 
because, before the call, MidiShare restaures the global context 
register of the application. 


Prototype

C Atari    : RcvAlarmPtr        MidiGetRcvAlarm(refNum);
C Mac ANSI : pascal RcvAlarmPtr MidiGetRcvAlarm(short refNum);
Pascal Mac : function MidiGetRcvAlarm(refNum: integer):RcvAlarmPtr;
Gfa Basic  : <not implemented>


Arguments

refNum : a 16-bit integer, the reference number of the application


Result

The result, a RcvAlarmPtr, it is the address of the receive alarm 
routine or NIL if no such routine where installed. 


Prototype of a RcvAlarm routine

C Atari    : void        MyRcvAlarm (refNum);
C Mac ANSI : pascal void MyRcvAlarm (short refNum);
Pascal Mac : procedure   MyRcvAlarm (refNum:integer);


Argument of a RcvAlarm routine

refNum     : a 16-bit integer, it is the reference number of the 
          application.


_____________________________________________________________________
Example (ANSI C)

Temporarily disable the application receive alarm.

RcvAlarmPtr p;
.....
p = MidiGetRcvAlarm( myRefNum );
MidiSetRcvAlarm( NIL );      /* Disable application receive alarm  */
.....
MidiSetRcvAlarm( p );        /* Restaure application receive alarm */


/#MidiGetSyncInfo
_____________________________________________________________________

Description

Fills a TSyncInfo record with informations about the current state of 
the MTC synchronisation.

Prototypes
C Atari    : void        MidiGetSyncInfo (p);
C Mac ANSI : pascal void MidiGetSyncInfo (SyncInfoPtr p);
Pascal Mac : procedure   MidiGetSyncInfo (p: SyncInfoPtr);
Gfa Basic  : procedure   midi_get_sync_info(p$)


Arguments

p: a SyncInfoPtr, a pointer to a TSyncInfo record

note for Gfa users : p$ is a string containing at least 34 characters.


description of a TSyncInfo record :

typedef struct TSyncInfo
{
  // the current MidiShare date (in milliseconds)
     long time;
  // the current reentrancy count of the interrupt handler
     long reenter;
  // the current synchronisation mode as defined by MidiSetSyncMode
     unsigned short syncMode;
  // the current synchronisation state (0 : unlocked 1 : locked)
     Byte syncLocked;
  // the current synchronisation port
     Byte syncPort;
  // the date MidiShare started beeing locked to external sync(in ms)
     long syncStart;
  // the date MidiShare stopped being locked to external sync (in ms)
     long syncStop;
  // the current offset (MidiGetExtTime() - MidiGetTime(), in ms)
     long syncOffset;
  // the current value for the timer (implementation dependent)
     long syncSpeed;
  // current count of breaks (transition from state locked to unlocked)
     long syncBreaks;
  // current synchronisation format (0:24f/s,1:25f/s,2:30DFf/s,3:30f/s)
     short syncFormat;
} TSyncInfo;


Note 1

syncMode is an unsigned 16-bits word of struture : xa000000pppppppp. 
x (bit 15) is used to choose between internal synchronisation (x=0) 
   and external synchronisation (x=1)
a (bit 14) is used to choose between synchronisation on port p (a=0) 
   and synchronisation on any port (a=1)
bit 13:8 are reserved for future use and must be set to 0.
p (bit 0:7) is the synchronisation port to be used when x=1 and a=0. 
When a=1 the port number is ignored, the first port with incomming MTC 
is used.


Note 2

While MidiShare is locked (syncLocked == 1) syncOffset is constant and 
we have the following relationships :
    MidiGetExtTime() == MidiGetTime() + syncOffset
    MidiInt2ExtTime(x) == x + syncOffset
    MidiExt2IntTime(x) == x - syncOffset


_____________________________________________________________________
Example (ANSI C)
Gives the SMPTE start location of the tape.

TSyncInfo       myInfo;
TSmpteLocation myLoc;
MidiGetSyncInfo(&myInfo);
MidiTime2Smpte( MidiInt2ExtTime(myInfo.syncStart), myInfo.syncFormat, 
                &myLoc);


/#MidiGetTime
_____________________________________________________________________

Description

Return in milliseconds the time past since the starting up of 
MidiShare.


Prototype

C Atari    : long        MidiGetTime();
C Mac ANSI : pascal long MidiGetTime();
Pascal Mac : Function    MidiGetTime : longint;
Gfa Basic  : Function    midi_get_time : longint


Arguments

none


Result

The result is a 32-bit integer, the elapsed time in milliseconds 
since the starting up of MidiShare. 


_____________________________________________________________________
Example (ANSI C)

A wait function :

void wait(long delay)
{
    long d;
    
    d = MidiGetTime() + delay;
    while (MidiGetTime() < d);
}


/#MidiGetVersion
_____________________________________________________________________

Description

Gives the version number of MidiShare
 

Prototype

C Atari    : short        MidiGetVersion();
C Mac ANSI : pascal short MidiGetVersion(void);
Pascal Mac : Function     MidiGetVersion : integer;       
Gfa Basic  : Function     midi_get_version : integer


Arguments

none


Result

The result is a 16-bit integer, the MidiShare version number. 
A result of 120 means <version 1.20>. 


_____________________________________________________________________
Example (ANSI C)

Print the MidiShare version number

void PrintVersion(void)
{
    printf( "MidiShare version : %4.2f\n", MidiGetVersion()/100.0);
}


/#MidiGrowSpace
_____________________________________________________________________

Description

try to increase the memory space of MidiShare.


Prototype

C Atari    : long        MidiGrowSpace( n);
C Mac ANSI : pascal long MidiGrowSpace( long n);
Pascal Mac : Function MidiGrowSpace( n : longint) : longint;
Gfa Basic  : <not implemented>


Arguments

n : the number of cells to increase the MidiShare memory space.


Result 

The result is a 32-bit integer, the number of new cells actually 
allocated.


_____________________________________________________________________
Example (ANSI C)

Add 1000 cells to MidiShare memory space.

void TryGrowSpace(void)
{
   printf( "Try to allocate 1000 cells : %ld\n", MidiGrowSpace(1000));
}

Note : on the Atari, MidiGrowSpace can only be used from a desk 
accessory, and not from a normal application.


/#MidiInt2ExtTime
_____________________________________________________________________

Description

Convert an internal time in millisecond to an external time. 
The convertion is made by adding the current offset between internal 
and external time.


Prototypes

C Atari    : long        MidiInt2ExtTime (time);
C Mac ANSI : pascal long MidiInt2ExtTime (long time)
Pascal Mac : Function    MidiGetExtTime( time : longint) : longint;
Gfa Basic  : Function    midi_int_2_ext_time(time%) : longint


Arguments

time : a 32-bits time in milliseconds


Result

the corresponding external time, a 32-bits value in milliseconds.


Note

When MidiShare is locked we have the following equivalence :

    MidiInt2ExtTime( MidiGetTime() ) == MidiGetExtTime()

We have also :

    TSyncInfo     myInfo;
    MidiGetSyncInfo(&myInfo);
    MidiInt2ExtTime(x) == x + myInfo.syncOffset


/#MidiIsConnected
_____________________________________________________________________

Description

Gives the state of a connection between two MidiShare applications. 
Connections allow real-time communications of midi events between 
applications.


Prototype

C Atari    : Boolean        MidiIsConnected( src, dest );
C Mac ANSI : pascal Boolean MidiIsConnected( short src, short dest );
Pascal Mac : Function MidiIsConnected( src, dest: integer) : boolean;
Gfa Basic  : Function midi_is_connected(src&,dest&) : boolean


Arguments

src  :     is the reference number of a source application
dest :     is the reference number of a destination application


Result

The result is true when a connection exist between the source and 
the destination, and false otherwise. 


_____________________________________________________________________
Example (ANSI C)

Print all the sources of an application

void PrintSources(short refNum)
{
    short     src;
    short     i;
    
    printf( "Sources of : %s\n", MidiGetName( refNum) );
    for( i = 1; i <= MidiCountAppls(); ++i )
    {
        src = MidiGetIndAppl(i);
        if ( MidiIsConnected(src, refNum) )
            printf(" %i : %s \n", src, MidiGetName( src ) );
    }
}


Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, the result of MidiGetName is a Pascal 
string that must be converted to a C string to be printed.


/#MidiNewCell
_____________________________________________________________________

Description

Allocates a simple memory cell from the MidiShare memory manager. For 
some special treatments, it may be useful to have access to the basic 
functions of the memory manager. All the events managed by MidiShare 
are implemented from fixed-sized cells (16 bytes).


Prototype

C Atari    : MidiEvPtr        MidiNewCell();
C Mac ANSI : pascal MidiEvPtr MidiNewCell(void);
Pascal Mac : Function         MidiNewCell : MidiEvPtr;  
Gfa Basic  : Function         midi_new_cell : MidiEvPtr


Arguments

none


Result

The result a MidiEvPtr, a pointer to a memory cell, or NIL when 
memory space is exhausted. 


_____________________________________________________________________
Example (ANSI C)

Allocate a new cell.

MidiEvPtr c;

c = MidiNewCell();

.....

MidiFreeCell(c);



Note : Cells allocated with MidiNewCell must be freed with 
MidiFreeCell and not with MidiFreeEv.


/#MidiNewEv
_____________________________________________________________________

Description

Allocates a new event of desirable type.


Prototype

C Atari    : MidiEvPtr        MidiNewEv( short typeNum );
C Mac ANSI : pascal MidiEvPtr MidiNewEv( short typeNum );
Pascal Mac : Function    MidiNewEv(typeNum: integer): MidiEvPtr;
Gfa Basic  : Function    midi_new_ev(typeNum&) : MidiEvPtr


Arguments

typeNum :     the type of event to be allocated


Result

The result a MidiEvPtr, a pointer to a MidiShare event of the 
desired type, or NIL if the MidiShare memory space is exhausted.


_____________________________________________________________________
Example (ANSI C)

A function for creating note events.


MidiEvPtr Note(long date, short pitch, short vel,
              long dur, short chan, short port)
{
    MidiEvPtr e;
    
    if ( e=MidiNewEv(typeNote) )
    {
        Date(e) = date; Pitch(e) = pitch; Vel(e) = vel;
        Dur(e) = dur; Chan(e) = chan; Port(e) = port;
    }
    return e;
}


/#MidiNewSeq
_____________________________________________________________________

Description

Allocation of a new empty sequence.


Prototype

C Atari    : MidiSeqPtr MidiNewSeq();
C Mac ANSI : pascal     MidiSeqPtr MidiNewSeq();
Pascal Mac : Function   MidiNewSeq : MidiSeqPtr; 
Gfa Basic  : Function   midi_new_seq : MidiSeqPtr


Arguments

none


Result

The result is a MidiSeqPtr, a pointer to an empty sequence. 


_____________________________________________________________________
Example (ANSI C)

Create a sequence of 10 Midi clocks.


MidiSeqPtr ClockSeq()
{
    MidiSeqPtr    s;
    MidiEvPtr    e;
    long    d;
    
    s = MidiNewSeq();
    for (d=0; d< 2500; d+=250) 
    {
        e = MidiNewEv (typeClock);
        Date(e) = d;
        MidiAddSeq (s, e);
    }
    return s;
}


/#MidiOpen
_____________________________________________________________________

Description

Opening of MidiShare. MidiOpen allows the recording of some 
information relative to the application context (its name, the 
value of the global data register, etc...), to allocate a reception 
FIFO and to attribute a unique reference number to the application.
In counterpart to any MidiOpen call, the application must call the 
MidiClose function before leaving, by giving its reference number 
as an argument. MidiShare can thus be aware of the precise number 
of active Midi applications. 


Prototype

C Atari    : short        MidiOpen( applName );
C Mac ANSI : pascal short MidiOpen( MidiName applName );
Pascal Mac : Function     MidiOpen( applName: midiName ): integer;
Gfa Basic  : Function     midi_open(applName$) : integer


Arguments

applName :     the name of the application.


Result

The result is a unique reference number identifing the application. 


_____________________________________________________________________
Example (ANSI C)

A DoNothing MidiShare application.

#include MidiShare.h
#include <stdio.h>

short    myRefNum;

main()
{
   if ( ! MidiShare() )     exit(1);   /* Check MidiShare loaded    */
   myRefNum = MidiOpen("Sample");      /* Ask for a reference number*/
   if ( myRefNum < 1 )     exit(1);    /* Check MidiOpen success    */
   printf( "refNum : %i \n", myRefNum);/* Print the reference number*/
   MidiClose(myRefNum);                /* And close                 */
}


Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, all strings passed as arguments of 
a MidiShare function must be Pascal strings. In the previous exemple,
one must write :         
myRefNum = MidiOpen("\pSample");


/#MidiReadSync
_____________________________________________________________________

Description

The MidiReadSync function reads and sets to NIL a memory address. 
This function is none-interruptible in order to make easier 
communication between the application tasks that run at interrupt 
level. It can be used to implement some sort of "mail boxe" in 
conjunction of MidiWriteSync.


Prototype

C Atari    : Ptr          MidiReadSync( adrMem );
C Mac ANSI : pascal void *MidiReadSync( void* adrMem) ;
Pascal Mac : Function     MidiReadSync( adrMem: univ ptr): ptr;
Gfa Basic  : Function     midi_read_sync(adrMem%) : ptr


Arguments

adrMem :     the address of a variable containing a 32-bit data.


Result

The result is the content of the variable. 


Side effect

Once read, the content of the variable is set to NIL. 


_____________________________________________________________________
Example (ANSI C)
                    << to be supplied >>


/#MidiSend
_____________________________________________________________________

Description

Sends an event. A copy of the event is sended to all the application 
destinations. The date field of the event is used to specify when 
destinations will actually receive the event.


Prototype

C Atari    : void        MidiSend( refNum, e );
C Mac ANSI : pascal void MidiSend( short refNum, MidiEvPtr e );
Pascal Mac : procedure   MidiSend( refNum: integer; e : MidiEvPtr);
Gfa Basic  : procedure   midi_send(refNum&,e%)


Arguments

refNum  : a 16-bit integer, it is the reference number of the 
          application.
e       : a MidiEvePtr, it is a pointer to the event to send.


_____________________________________________________________________
Example (ANSI C)

A receive alarm that processes all the received events by adding a 
one second delay to their date.

void OneSecDelay (short refNum)
{
    MidiEvPtr    e;
    long n;

    for ( n = MidiCountEvs(refNum); n > 0; --n ) 
    {                                
        e = MidiGetEv(refNum);  /* Get an event from the fifo    */
        Date(e) += 1000;        /* Add 1000 ms to its date       */
        MidiSend(refNum,e);     /* Then send the event           */
    }
}

......

MidiSetRcvAlarm(myRefNum,OneSecDelay);/* Activate the receive alarm */


Note : such a procedure can be called repeatedly in the main event 
loop of the application, but for really accurate time control, it 
must be installed as a receive alarm with MidiSetRcvAlarm.

Note for Mac users : MidiShare was originaly developed for Pascal 
on the Macintosh. Consequently, in C, all procedure passed as 
arguments of a MidiShare function must be declared as Pascal. In 
the previous exemple, OneSecDelay must be declared as :     
pascal void OneSecDelay (short refNum)


/#MidiSendAt
_____________________________________________________________________

Description

Sends an event. A copy of the event is sended to all the application 
destinations. The date argument is used to specify when destinations 
will actually receive the event.


Prototype

C Atari    : void        MidiSendAt( refNum, e );
C Mac ANSI : pascal void MidiSendAt( short refNum, MidiEvPtr e, 
                                                        lond d );
Pascal Mac : procedure   MidiSendAt( refNum:integer; e:MidiEvPtr; 
                                                      d:longint);
Gfa Basic  : procedure   midi_send_at(refNum&,e%,d%)


Arguments

refNum  : a 16-bit integer, it is the reference number of the 
          application.
e       : a MidiEvePtr, it is a pointer to the event to send.
d       : a 32-bit integer, the date when destinations will 
          receive the event.


_____________________________________________________________________
Example (ANSI C)

Equivalence between MidiSend, MidiSendAt and MidiSendIm :

MidiSendAt(myRefNum,e,MidiGetTime());

    is equivalent to :

MidiSendIm(myRefNum,e);

    is equivalent to :

Date(e) = MidiGetTime();
MidiSend( myRefNum, e );


/#MidiSendIm
_____________________________________________________________________

Description

Immediatly sends an event. A copy of the event is sended to all the 
application destinations.


Prototype

C Atari    : void        MidiSendIm( refNum, e );
C Mac ANSI : pascal void MidiSendIm( short refNum, MidiEvPtr e );
Pascal Mac : procedure   MidiSendIm( refNum:integer; e:MidiEvPtr );
Gfa Basic  : procedure   midi_send_im(refNum&,e%)


Arguments

refNum  : a 16-bit integer, it is the reference number of the 
          application.
e       : a MidiEvePtr, it is a pointer to the event to send.


_____________________________________________________________________
Example (ANSI C)

equivalence between MidiSend, MidiSendAt and MidiSendIm :


MidiSendIm(myRefNum,e);

    is equivalent to :

MidiSendAt(myRefNum,e,MidiGetTime());

    is equivalent to :

Date(e) = MidiGetTime();
MidiSend( myRefNum, e );


/#MidiSetApplAlarm
_____________________________________________________________________

Description

Defines the context alarm of an application. These alarm will be 
called by MidiShare on every application global context modifications 
(opening and closing of applications, opening and closing of midi 
ports, changes in connections between applications).


Prototype

C Atari    : void        MidiSetApplAlarm(short refNum, 
                                             ApplAlarmPtr alarm);
C Mac ANSI : pascal void MidiSetApplAlarm(short refNum, 
                                             ApplAlarmPtr alarm);
Pascal Mac : Procedure   MidiSetApplAlarm(refNum:integer; 
                                             alarm:ApplAlarmPtr);  
Gfa Basic  : <not implemented> see note below


Arguments

refNum :    a 16-bit integer, it is the reference number of the 
            application.
alarm  :    a ApplAlarmPtr, a  pointer to the application context 
            alarm routine.


Prototype of a ApplAlarm routine

C Atari       : void        MyApplAlarm (refNum, code);
Turbo C Atari : void cdecl  MyApplAlarm (short refNum, long code);
C Mac ANSI    : pascal void MyApplAlarm (short refNum, long code);
Pascal Mac    : procedure   MyApplAlarm (refNum:integer; code:longint);


Argument of a ApplAlarm routine

refNum  : a 16-bit integer, it is the reference number of the 
          application.
code    : a 32-bit integer, the context modification code. 


Note for Gfa users : for Gfa Basic, it is a particular implementation 
of this function named gfa_set_appl_alarm :
    procedure gfa_set_appl_alarm(refnum&,alarm_code%)
alarm_code% is a variable which will be set every time a global 
context modification occur with the same meaning of the code passed 
to the ApplAlarm routine. It is the responsability of the application 
to detect if this variable changed.

_____________________________________________________________________
Example (ANSI C)
                    << to be supplied >>


/#MidiSetField
_____________________________________________________________________

Description

Attributes a value to the i index data field of an event. The access 
to the compulsory fields of the event is directly done. But the 
access to the variables fields is achieved thru the MidiSetField 
and MidiGetField functions. The procedure deals with the conversion 
of this value into the concerned field format (8, 16 or 32-bit).


Prototype

C Atari    : void        MidiSetField( MidiEvPtr e, long f, long v);
C Mac ANSI : pascal void MidiSetField( MidiEvPtr e, long f, long v);
Pascal Mac : procedure   MidiSetField( e:MidiEvPtr; f:longint; 
                                                   v:longint );
Gfa Basic  : procedure   midi_set_field(e%,f%,v%)


Arguments

e :     a MidiEvPtr, a pointer to the event to modifie
f :     a 32-bit integer, the index number of the field to modify 
        ( from 0 to MidiCountFields(e)-1 )
v :     a 32-bit value to put in the field. This value will be 
        converted to the right size (8, 16 or 32-bit)


_____________________________________________________________________
Example (ANSI C)
                    << to be supplied >>


/#MidiSetFilter
_____________________________________________________________________

Description

Associates a filter to an application. Each application can select 
the events to be received by using a filter. The filtering process 
is local to the application and has no influence on the events 
received by the other applications. The implementation of these 
filters is achieved by two routines : MidiSetFilter and MidiGetFilter.


Prototype

C Atari    : void        MidiSetFilter( refNum, filter );
C Mac ANSI : pascal void MidiSetFilter( short refNum, 
                                         FilterPtr filter);
Pascal Mac : procedure   MidiSetFilter( refNum: integer; 
                                         filter: FilterPtr );   
Gfa Basic  : procedure   midi_set_filter(refNum&,filter%)


Arguments

refNum  : a 16-bit integer, it is the reference number of the 
          application.
filter  : a FilterPtr, a pointer to the application filter. 


_____________________________________________________________________
Example (ANSI C)
                    << to be supplied >>


/#MidiSetInfo
_____________________________________________________________________

Description

Defines the global information area of an application. The Macintosh 
desk accessories cannot have global variables. To make up for this 
drawback, the MidiSetInfo routine allows each application to define 
a data area. This area remains accessible by MidiGetInfo function, 
even during the alarm, and also serves as a global context to 
desk accessories.


Prototype

C Atari    : void        MidiSetInfo( refNum, infoZone );
C Mac ANSI : pascal void MidiSetInfo( short refNum, void* infoZone );
Pascal Mac : procedure   MidiSetInfo( refNum: integer; infoZone: Ptr);   
Gfa Basic  : procedure   midi_set_info(refNum&,infoZone%)


Arguments

refNum  : a 16-bit integer, it is the reference number of the 
          application.
infoZone : an arbitrary 32-bit value, generaly a pointer or a handle. 


_____________________________________________________________________
Example (ANSI C)
                    << to be supplied >>


/#MidiSetName
_____________________________________________________________________

Description

Changes the name of an application.


Prototype

C Atari    : void        MidiSetName( refNum, name );
C Mac ANSI : pascal void MidiSetName( short refNum, MidiName name );
Pascal Mac : procedure   MidiSetName( refNum: integer; name: midiName);
Gfa Basic  : procedure   midi_set_name(refNum&,name$)


Arguments

refNum  : a 16-bit integer, it is the reference number of the 
          application.
name    : a MidiName, the new application name.


_____________________________________________________________________
Example (ANSI C)
                    << to be supplied >>


/#MidiSetPortState
_____________________________________________________________________

Description

Opening and closing of a Midi port. The implementation of Midi ports 
is controlled by the MidiSetPortState and MidiGetPortState routines. 
These must be used with care since they affect all the applications. 
A closed port is available for other uses (printing, AppleTalk, 
etc...). The Midi applications holding a "context alarm" will be 
informed of this change in the ports state.


Prototype

C Atari    : void        MidiSetPortState( port, state );
C Mac ANSI : pascal void MidiSetPortState( short port, Boolean state);
Pascal Mac : procedure   MidiSetPortState( port: integer; 
                                           state: boolean );   
Gfa Basic  : procedure   midi_set_port_state(port&,state!)


Arguments

port  : a 16-bit integer, the port number to control.
state : a Boolean, True : to open a port, False : to close a port.


_____________________________________________________________________
Example (ANSI C)
                    << to be supplied >>


/#MidiSetRcvAlarm
_____________________________________________________________________

Description

Defines the event reception alarm of an application. The alarm will 
be automatically called by MidiShare to inform the application of 
the presence of new events in its reception fifo. This alarm is 
always called under interruption. It must not use, directly or
indirectly, the Macintosh Memory Manager. It can freely access to 
all the others MidiShare functions, particularly to the event 
management (but not MidiOpen and MidiClose). It can also use 
application global variables, since MidiShare restaures its global 
context register, before the call.


Prototype of MidiSetRcvAlarm

C Atari    : void        MidiSetRcvAlarm( refNum, alarm );
C Mac ANSI : pascal void MidiSetRcvAlarm( short refNum, 
                                             RcvAlarmPtr alarm );
Pascal Mac : Procedure   MidiSetRcvAlarm(refNum:integer;
                                            alarm:RcvAlarmPtr );  
Gfa Basic  : <not implemented>


Arguments of MidiSetRcvAlarm

refNum : a 16-bit integer, the reference number of the application
alarm  : a RcvAlarmPtr, a pointer to a receive alarm routine or 
         NIL to disable receive alarms.


Prototype of a RcvAlarm routine

C Atari       : void        MyRcvAlarm (refNum);
Turbo C Atari : void cdecl  MyRcvAlarm (short refNum);
C Mac ANSI    : pascal void MyRcvAlarm (short refNum);
Pascal Mac    : procedure   MyRcvAlarm (refNum:integer);


Argument of a RcvAlarm routine

refNum     : a 16-bit integer, it is the reference number of the 
          application.


_____________________________________________________________________
Example (ANSI C)

A receive alarm that processes all the received events by adding to 
their date a one second delay.

void OneSecDelay (short refNum)
{
    MidiEvPtr    e;
    long n;

    for ( n = MidiCountEvs(refNum); n > 0; --n ) 
    {                                
        e = MidiGetEv(refNum);  /* Get an event from the fifo    */
        Date(e) += 1000;        /* Add 1000 ms to its date       */
        MidiSend(refNum,e);     /* Then send the event           */
    }
}

......
  
MidiSetRcvAlarm(myRefNum,OneSecDelay);/* Install the receive alarm */


Note : one such procedure can be called repeatedly in the main event 
loop of the application, but for really accurate time control, it 
must be installed as a receive alarm with MidiSetRcvAlarm.

Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, all procedure passed as arguments 
of a MidiShare function must be declared as Pascal. In the previous 
exemple, OneSecDelay must be declared as :     
pascal void OneSecDelay (short refNum)


/#MidiSetSyncMode
_____________________________________________________________________

Description

Set the synchronisation mode of MidiShare.


Prototypes

C Atari    : void        MidiSetSyncMode (mode);
C Mac ANSI : pascal void MidiSetSyncMode (unsigned short mode);
Pascal Mac : procedure   MidiSetSyncMode (mode: integer);
Gfa Basic  : procedure   midi_set_sync_mode(mode&)


Arguments

mode : an unsigned 16-bits word of struture : xa000000pppppppp. 
x (bit 15) is used to choose between internal synchronisation (x=0) 
   and external synchronisation (x=1)
a (bit 14) is used to choose between synchronisation on port p (a=0) 
   and synchronisation on any port (a=1)
bit 13:8 are reserved for future use and must be set to 0.
p (bit 0:7) is the synchronisation port to be used when x=1 and a=0. 
When a=1 the port number is ignored, the first port with incomming 
MTC is used.


Example 1 (ANSI C)
Set the synchronisation to external, on any port.

    MidiSetSyncMode(MIDISyncExternal | MIDISyncAnyPort);


Example 2 (ANSI C)
Set the synchronisation to external, on port 18.

    MidiSetSyncMode(MIDISyncExternal | 18);


Example 3 (ANSI C)
Set the synchronisation to internal.

    MidiSetSyncMode(MIDISyncInternal);


/#MidiShare
_____________________________________________________________________

Description

Tests MidiShare code presence in memory by trying to recognise a 
special pattern. First of all, an application must make sure that 
MidiShare is in memory. This test is done thanks to the MidiShare 
function.


Prototype

C Atari    : Boolean        MidiShare();
C Mac ANSI : pascal Boolean MidiShare(void);
Pascal Mac : Function       MidiShare : boolean;
Gfa Basic  : Function       midi_share : boolean


Arguments

none


Result

The result is true when MidiShare is loaded, false otherwise. 


_____________________________________________________________________
Example (ANSI C)

A DoNothing MidiShare application.

#include MidiShare.h
#include <stdio.h>

short    myRefNum;

main()
{
   if ( ! MidiShare() )     exit(1);    /* Check MidiShare loaded */
   myRefNum = MidiOpen("Sample");       /* Ask for a ref. number  */
   if ( myRefNum < 1 )     exit(1);     /* Check MidiOpen success */
   printf( "refNum : %i \n", myRefNum); /* Print the ref. number  */
   MidiClose(myRefNum);                 /* And close              */
}


Note for Mac users : MidiShare was originaly developed for Pascal on 
the Macintosh. Consequently, in C, all strings passed as arguments 
of a MidiShare function must be Pascal strings. In the previous 
exemple, one must write :         
myRefNum = MidiOpen("\pSample");


/#MidiSmpte2Time
_____________________________________________________________________

Description

Convert an SMPTE location to a time in millisecond.


Prototypes

C Atari    : long        MidiSmpte2Time (loc);
C Mac ANSI : pascal long MidiSmpte2Time (SmpteLocPtr loc);
Pascal Mac : Function    MidiSmpte2Time (loc: SmpteLocPtr): longint;
Gfa Basic  : Function    midi_smpte_2_time(loc%) : longint


Arguments

loc : a pointer to a TSmpteLocation record to be converted in 
      milliseconds.


Result

a 32-bits time in milliseconds


Description of a TSmpteLocation

typedef struct TSmpteLocation *SmpteLocPtr;
typedef struct TSmpteLocation
{
     short    format;    // (0:24 f/s, 1:25 f/s, 2:30DF f/s, 3:30 f/s)
     short    hours;     // 0..23
     short    minutes;   // 0..59
     short    seconds;   // 0..59
     short    frames;    // 0..30 (according to format)
     short    fracs;     // 0..99 (1/100 of frames)
} TSmpteLocation; 


_____________________________________________________________________
Example (ANSI C)
Gives the SMPTE location from its current format to 30 drop frame 
(format 2).

    TSmpteLocation myLoc; 
...
// we suppose here myLoc filled with an Smpte location

    MidiTime2Smpte( MidiSmpte2Time(&myLoc), 2, &myLoc);

// now myLoc is filled with the same Smpte location but in 30 drop 
frame format.


/#MidiTask
_____________________________________________________________________

Description

On the same way as MidiDTask, MidiTask allows to realize a time 
delayed procedure call ; but on the reverse to MidiDTask, the call 
is achieved under interruption as soon as falling time is due. 


Prototype of MidiTask

C Atari    : MidiEvPtr MidiTask (MyProc, date, refNum, a1, a2, a3);
C Mac ANSI : pascal MidiEvPtr MidiTask (TaskPtr MyProc, long date, 
                             short refNum, long a1, long a2, long a3);
Pascal Mac : Function MidiTask (MyProc:TaskPtr; date:longint; 
                         refNum:integer; a1,a2,a3: longint):MidiEvPtr;  
Gfa Basic  : <not implemented>


Arguments of MidiTask

MyProc   : a TaskPtr, it is the address of the routine to be called.
date     : a 32-bit integer, it is the date at which this call is 
           scheduled. 
refNum   : a 16-bit integer, it is the reference number of the 
           application.
a1,a2,a3 : are 32-bit integers left at the user's disposal, as 
           arguments to MyProc


Result of MidiTask

The result, a MidiEvPtr, is a pointer to a typeProcess MidiShare 
event. The result is NIL if MidiShare run out of memory.


Prototype of MyProc

C Atari       : void        MyProc (date, refNum, a1, a2, a3);
Turbo C Atari : void cdecl  MyProc (long date, short refNum, 
                                    long a1, long a2, long a3);
C Mac ANSI    : pascal void MyProc (long date, short refNum, 
                                    long a1, long a2, long a3);
Pascal Mac    : procedure   MyProc (date:longint; refNum:integer; 
                                               a1,a2,a3: longint);


Argument of MyProc

date     : a 32-bit integer, it is the date of the call . 
refNum   : a 16-bit integer, it is the reference number of the 
           application.
a1,a2,a3 : are 32-bit integers that can be freely used.


_____________________________________________________________________
Example (ANSI C)

Schedule a procedure Action() call 1000 ms ahead.


MidiEvPtr    myTask;

myTask = MidiTask(Action,MidiGetTime()+1000,myRefNum, a1, a2, a3);

Note : The result, in myTask, can be used to test the success of 
MidiTask. It can also be used by MidiForgetTask to try to "forget" 
a scheduled task before it happens.


/#MidiTime2Smpte
_____________________________________________________________________

Description

Convert a time in millisecond to an SMPTE location.


Prototypes

C Atari    : void        MidiTime2Smpte (time, format, loc);
C Mac ANSI : pascal void MidiTime2Smpte (long time, short format, 
                                         SmpteLocPtr loc);
Pascal Mac : procedure   MidiTime2Smpte (time:longint; format:integer; 
                                          loc: SmpteLocPtr);
Gfa Basic  : procedure   midi_time_2_smpte(time%,format&,loc%)


Arguments

time  : a 32-bits time in milliseconds to convert in an Smpte location
format: a 16-bits integer, the Smpte format to be used : (0 : 24 f/s, 
         1 : 25 f/s, 2 : 30DF f/s, 3 : 30 f/s)
loc   : a pointer to a TSmpteLocation record to be filled with the 
         resulting Smpte location.


Description of a TSmpteLocation

typedef struct TSmpteLocation *SmpteLocPtr;
typedef struct TSmpteLocation
{
     short    format;  // (0:24 f/s, 1:25 f/s, 2:30DF f/s, 3:30 f/s)
     short    hours;   // 0..23
     short    minutes; // 0..59
     short    seconds; // 0..59
     short    frames;  // 0..30 (according to format)
     short    fracs;   // 0..99 (1/100 of frames)
} TSmpteLocation; 


_____________________________________________________________________
Example (ANSI C)
Gives the SMPTE start location of the tape.

    TSyncInfo     myInfo;
    TSmpteLocation myLoc;

    MidiGetSyncInfo(&myInfo);
    MidiTime2Smpte( MidiInt2ExtTime(myInfo.syncStart), 
	                myInfo.syncFormat, &myLoc);


/#MidiTotalSpace
_____________________________________________________________________

Description

Gives the total space. MidiTotalSpace allows to know at any time the 
total number of cells allocated by the MidiShare memory manager at 
startup.  


Prototype

C Atari    : long        MidiTotalSpace();
C Mac ANSI : pascal long MidiTotalSpace(void);
Pascal Mac : Function    MidiTotalSpace : longint;
Gfa Basic  : Function    midi_total_space : longint


Arguments

none


Result

the result is a 32-bit integer, the total number of cells in the 
MidiShare memory manager.


_____________________________________________________________________
Example (ANSI C)

Print informations about MidiShare memory space.

void PrintMemInfo(void)
{
 printf("MidiShare memory :\n");
 printf("free space  : %i cells\n", MidiFreeSpace());
 printf("used space  : %i cells\n", MidiTotalSpace()-MidiFreeSpace());
 printf("total space : %i cells\n", MidiTotalSpace());
}


/#MidiWriteSync
_____________________________________________________________________

Description

Writes a 32-bit value to a variable only if the previous variable 
content was NIL. This function is non-interruptible in order to make 
easier communication between the application tasks that run at 
interrupt level. It can be used to implement some sort of "mail boxes" 
in conjunction of MidiReadSync.


Prototype

C Atari    : Ptr          MidiWriteSync( adrMem, val );
C Mac ANSI : pascal void* MidiWriteSync( void *adrMem, void *val );
Pascal Mac : Function     MidiWriteSync( adrMem:univ ptr; 
                                            val:univ ptr):ptr;
Gfa Basic  : Function     midi_write_sync(adrMem%,val%)


Arguments

adrMem :     is the addresse of a variable to modifie.
val    :     is a 32-bit value to write.

Result

The result is the previous content of the variable. 


_____________________________________________________________________
Example (ANSI C)
                    << to be supplied >>


/~EVENT'S TYPES

/#typeActiveSens    (code 15)
_____________________________________________________________________

Event Description
A Real Time ActiveSens message. 


Fields : ActiveSens events have no field.


_____________________________________________________________________
Example (ANSI C)
Creates a ActiveSens event. Return a pointer to the event or NIL if 
there is no more memory space.

MidiEvPtr ActiveSens ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeActiveSens ) )
    /* Allocate a new event. Check not NIL*/ 
    {
        Date(e) = date; /* These informations are common to all*/
        Port(e) = port; /* kind of events */
    }
    return e;
}


/#typeChanPress     (code 6)
_____________________________________________________________________

Event Description
A Channel pressure message with pressure value. 


Fields : ChanPress events have 1 field numbered 0 :

    0 - A channel pressure value from 0 to 127. (Field size : 1 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a ChanPress event. Return a pointer to the event or NIL if 
there is no more memory space.

MidiEvPtr ChanPress( long date, short press, short chan, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeChanPress ) )
    /* Allocate a new event. Check not NIL*/ 
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,press); /* Field particular to ChanPress */
    }
    return e;
}


/#typeClock         (code 10)
_____________________________________________________________________

Event Description
A Real Time Clock message. 


Fields : Clock events have no field.


_____________________________________________________________________
Example (ANSI C)
Creates a Clock event. Return a pointer to the event or NIL if there 
is no more memory space.

MidiEvPtr Clock ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeClock ) )
    /* Allocate a new event. Check not NIL*/ 
    {
        Date(e) = date;  /* These informations are common to all */
        Port(e) = port;  /* kind of events */
    }
    return e;
}

/#typeContinue      (code 12)
_____________________________________________________________________

Event Description
A Real Time Continue message. 


Fields : Continue events have no field.

_____________________________________________________________________
Example (ANSI C)
Creates a Continue event. Return a pointer to the event or NIL if 
there is no more memory space.

MidiEvPtr Continue ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeContinue ) )
    /* Allocate a new event. Check not NIL*/ 
    {
        Date(e) = date;  /* These informations are common to all */
        Port(e) = port;  /* kind of events */
    }
    return e;
}

/#typeCopyrigth     (code 136)
_____________________________________________________________________

Event Description
A copyright event (from the MidiFile 1.0 specification). This event 
cannot be sent to external Midi devices.


Fields : typeCopyrigth events have a variable number of character 
         fields. 


_____________________________________________________________________
Example 1 (ANSI C)
Creates a typeCopyrigth event from a character string. Return a 
pointer to the event or NIL if there is not enough memory space.

MidiEvPtr Copyrigth ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeCopyrigth) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;      /* These informations are common to all */
        Chan(e) = chan;      /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++)  /* Build the event while counting the*/
            MidiAddField(e ,*s); /* characters of the original string */
        if (c != MidiCountFields(e)) {
        /* Check the length of the event*/
            MidiFreeEv(e);      /* if we run out of memory : free the */
            return 0;           /* event and return NIL */
        }
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Convert a typeCopyrigth event into a character string. 
Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;
    
    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}


/#typeCtrl14b       (code 131)
_____________________________________________________________________

Event Description
A Control Change event with a controller number form 0 to 31 and 
a 14-bits value. When a typeCtrl14b event is sent to external Midi 
devices, actually two control change messages are sent, the first one 
for the MSB part of the value and the second one for the LSB part of 
the value. The message for the LSB part is sent only when the LSB part 
of the value is different from 0.


Fields : Ctrl14b events have 2 fields numbered from 0 to 1 :

    0 - A control number from 0 to 31. (Field size : 2 byte)
    1 - A control value from 0 to 16383. (Field size : 2 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a CtrlChange event. Return a pointer to the event or NIL if 
there is no more memory space.

MidiEvPtr CtrlChange14b( long date, short ctrl, short val, short chan, 
                         short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeCtrl14b ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events  */
        Port(e) = port;
        MidiSetField(e,0,ctrl); /* Fields particular to CtrlChange  */
        MidiSetField(e,1,val);
    }
    return e;
}

/#typeCtrlChange    (code 4)
_____________________________________________________________________

Event Description
A Control Change message with controller and value. 


Fields : CtrlChange events have 2 fields numbered from 0 to 1 :

    0 - A control number from 0 to 127. (Field size : 1 byte)
    1 - A control value from 0 to 127. (Field size : 1 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a CtrlChange event. Return a pointer to the event or NIL if 
there is no more memory space.

MidiEvPtr CtrlChange( long date, short ctrl, short val, short chan, 
                      short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeCtrlChange ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,ctrl); /* Fields particular to CtrlChange */
        MidiSetField(e,1,val);
    }
    return e;
}

/#typeChanPrefix    (code 142)
_____________________________________________________________________

Event Description
A channel prefix event (from the MidiFile 1.0 specification). This 
event cannot be sent to external Midi devices.


Fields : typeChanPrefix events have one field. 

    0 - A channel prefix number from 0 to 15. (Field size : 1 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a typeChanPrefix event. Return a pointer to the event or NIL 
if there is not enough memory space.

MidiEvPtr ChanPrefix ( long date, short prefix)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeChanPrefix))
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;
        MidiSetField( e, 0, prefix);
    }
    return e;
}


/#typeCuePoint      (code 141)
_____________________________________________________________________

Event Description
A cue point event (from the MidiFile 1.0 specification). This event 
cannot be sent to external Midi devices.


Fields : typeCuePoint events have a variable number of character fields. 


_____________________________________________________________________
Example 1 (ANSI C)
Creates a typeCuePoint event from a character string. Return a pointer 
to the event or NIL if there is not enough memory space.

MidiEvPtr CuePoint ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeCuePoint))
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++) /* Build the event while counting the */
            MidiAddField(e ,*s); /* characters of the original string */
        if (c != MidiCountFields(e)){ /* Check the length of the event*/
            MidiFreeEv(e);      /* if we run out of memory : free the */
            return 0;           /* event and return NIL */
        }
    }
    return e;
}

_____________________________________________________________________
Example 2 (ANSI C)
Convert a typeCuePoint event into a character string. 
Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;
    
    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}


/#typeDProcess      (code 129)
_____________________________________________________________________

Event Description
DProcess events are automatically created by MidiDTask. They are used 
to realize time delayed procedure call. Once the scheduling date is 
due, the routine is not automatically executed, but stored in a special 
list.It is the application responsability to execute, one by one, those 
pending tasks using MidiExec1DTask.


Fields : DProcess events have 4 fields numbered from 0 to 3 :

    0 - a TaskPtr, the adress of the procedure to call. 
        (Field size:4 byte)
    1 - the first argument of the procedure. (Field size : 4 byte)
    2 - the second argument of the procedure. (Field size : 4 byte)
    3 - the third argument of the procedure. (Field size : 4 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a DProcess event in the same way than MidiDTask.

MidiEvPtr MakeDTask ( TaskPtr proc, long date, short refNum, long arg1,
                    long arg2, long arg3)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeDProcess ) )
    /* Allocate a new event. Check not NIL */ 
    {
        MidiSetField(e, 0, (long)proc); /* Fill the 4 fields */
        MidiSetField(e, 1, arg1);
        MidiSetField(e, 2, arg2);
        MidiSetField(e, 3, arg3);
        MidiSendAt(refNum, e, date); /* and schedule the differed task*/
    }
    return e;
}


/#typeEndTrack      (code 143)
_____________________________________________________________________

Event Description
An end of track event (from the MidiFile 1.0 specification). This event 
cannot be sent to external Midi devices.


Fields : typeEndTrack  events have no field. 


_____________________________________________________________________
Example (ANSI C)
Creates a typeEndTrack  event. Return a pointer to the event or NIL 
if there is not enough memory space.

MidiEvPtr EndTrack ( long date )
{
    MidiEvPtr e;

    if ( e = MidiNewEv(typeEndTrack))
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;
    }
    return e;
}


/#typeInstrName     (code 138)
_____________________________________________________________________

Event Description
An instrument name event (from the MidiFile 1.0 specification). This 
event cannot be sent to external Midi devices.


Fields : typeInstrName events have a variable number of character 
         fields. 


_____________________________________________________________________
Example 1 (ANSI C)
Creates a typeInstrName event from a character string. Return a pointer 
to the event or NIL if there is not enough memory space.

MidiEvPtr InstrName ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeInstrName) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++)  /* Build the event while counting the*/
            MidiAddField(e ,*s); /* characters of the original string */
        if (c != MidiCountFields(e)){ /* Check the length of the event*/
            MidiFreeEv(e);       /* if we run out of memory : free the*/
            return 0;            /* event and return NIL */
        }
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Convert a typeInstrName event into a character string. 
Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;
    
    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}


/#typeKeyOff        (code 2)
_____________________________________________________________________

Event Description
A Note Off message with pitch and velocity. 


Fields : KeyOff events have 2 fields numbered from 0 to 1 :

    0 - Pitch, a note number from 0 to 127. (Field size : 1 byte)
    1 - Vel, a note velocity from 0 to 127. (Field size : 1 byte)


_____________________________________________________________________
Example 1 (ANSI C)
Creates a KeyOff event. Return a pointer to the event or NIL if there 
is no more memory space. Fields are modified using MidiSetField instead 
of direct structure access.

MidiEvPtr KeyOff(long date,short pitch,short vel,short chan,short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyOff ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,pitch);/*These fields are particular to KeyOff*/
        MidiSetField(e,1,vel);
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Creates a KeyOff event. Return a pointer to the event or NIL if there 
is no more memory space. Fields are modified using direct structure 
access instead of MidiSetField.

MidiEvPtr KeyKeyOff(long date,short pitch,short vel,short chan,
                    short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyOff ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        Pitch(e) = pitch;   /* These fields are particular to KeyOff*/
        Vel(e)  = vel;
    }
    return e;
}


/#typeKeyOn         (code 1)
_____________________________________________________________________

Event Description
A Note On message with pitch and velocity. 


Fields : KeyOn events have 2 fields numbered from 0 to 1 :

    0 - Pitch, a note number from 0 to 127. (Field size : 1 byte)
    1 - Vel, a note velocity from 0 to 127. (Field size : 1 byte)


_____________________________________________________________________
Example 1 (ANSI C)
Creates a KeyOn event. Return a pointer to the event or NIL if there 
is no more memory space. Fields are modified using MidiSetField 
instead of direct structure access.

MidiEvPtr KeyOn(long date,short pitch,short vel,short chan,short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyOn ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,pitch);/*These fields are particular to KeyOn*/
        MidiSetField(e,1,vel);
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Creates a KeyOn event. Return a pointer to the event or NIL if there 
is no more memory space. Fields are modified using direct structure 
access instead of MidiSetField.

MidiEvPtr KeyOn(long date,short pitch,short vel,short chan,short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyOn ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        Pitch(e) = pitch;   /* These fields are particular to KeyOn */
        Vel(e)  = vel;
    }
    return e;
}


/#typeKeyPress      (code 3)
_____________________________________________________________________

Event Description
A Polyphonic Key Pressure message with pitch and pressure. 


Fields : KeyPress events have 2 fields numbered from 0 to 1 :

    0 - Pitch, a note number from 0 to 127. (Field size : 1 byte)
    1 - Press, a key pressure from 0 to 127. (Field size : 1 byte)


_____________________________________________________________________
Example 1 (ANSI C)
Creates a KeyPress event. Return a pointer to the event or NIL if there 
is no more memory space. Fields are modified using MidiSetField instead 
of direct structure access.

MidiEvPtr KeyPress(long date,short pitch,short press,short chan,
                   short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyPress ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,pitch);/*These fields are particular to KeyPress*/
        MidiSetField(e,1,press);
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Creates a KeyPress event. Return a pointer to the event or NIL if there 
is no more memory space. Fields are modified using direct structure 
access instead of MidiSetField.

MidiEvPtr KeyPress(long date,short pitch,short press,short chan,
                   short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyPress ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        Pitch(e) = pitch;  /* These fields are particular to KeyPress*/
        Vel(e)  = press;   /* Same byte than velocity */
    }
    return e;
}


/#typeKeySign       (code 147)
_____________________________________________________________________

Event Description
A Key Signature event (form the MidiFile 1.0 specification). This event 
cannot be sent to external Midi devices. 


Fields : typeKeySign events have 2 fields :

    0 - from -7 (7 flats) to 7 (7 sharps), (8-bits field)
    1 - form 0 (major key) to 1 (minor key), (8-bits field)


_____________________________________________________________________
Example (ANSI C)
Creates a Key Signature event. Return a pointer to the event or NIL if 
there is no more memory space.

MidiEvPtr KeySign (long date, long sharpflats, long minor)
{
    MidiEvPtr e;

    if ( e = MidiNewEv(typeKeySign))
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;
        MidiSetField(e, 0, sharpflats);
        MidiSetField(e, 1, minor);
    }
    return e;
}


/#typeLyric         (code 139)
_____________________________________________________________________

Event Description
A lyric event (from the MidiFile 1.0 specification). This event cannot 
be sent to external Midi devices.


Fields : typeLyric events have a variable number of character fields. 


_____________________________________________________________________
Example 1 (ANSI C)
Creates a typeLyric event from a character string. Return a pointer to 
the event or NIL if there is not enough memory space.

MidiEvPtr Lyric ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeLyric) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++) /* Build the event while counting the */
            MidiAddField(e ,*s);/* characters of the original string  */
        if (c != MidiCountFields(e)){ /* Check the length of the event*/
            MidiFreeEv(e);  /* if we run out of memory : free the */
            return 0;       /* event and return NIL */
        }
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Convert a typeLyric event into a character string. Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;
    
    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}


/#typeMarker        (code 140)
_____________________________________________________________________

Event Description
A marker event (from the MidiFile 1.0 specification). This event cannot 
be sent to external Midi devices.


Fields : typeMarker events have a variable number of character fields. 


_____________________________________________________________________
Example 1 (ANSI C)
Creates a typeMarker event from a character string. Return a pointer 
to the event or NIL if there is not enough memory space.

MidiEvPtr Marker ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeMarker))
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++) /* Build the event while counting the */
            MidiAddField(e ,*s);/* characters of the original string  */
        if (c != MidiCountFields(e)){ /* Check the length of the event*/
            MidiFreeEv(e);      /* if we run out of memory : free the */
            return 0;           /* event and return NIL */
        }
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Convert a typeMarker event into a character string. Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;
    
    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}


/#typeNonRegParam   (code 132)
_____________________________________________________________________

Event Description
A Non Registred Parameter event with a 14-bits parameter number and 
a 14-bits parameter value. When a typeNonRegParam event is sent to 
external Midi devices, actually four control change messages are sent, 
two to select the non-registerd parameter number, and two for the 
parameter value using the 14-bits data-entry controller.


Fields : typeNonRegParam events have 2 fields numbered from 0 to 1 :

    0 - A Non Registred Parameter number from 0 to 16383. 
       (Field size : 2 byte)
    1 - A parameter value from 0 to 16383. (Field size : 2 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a Non Registred Parameter event. Return a pointer to the event 
or NIL if there is no more memory space.

MidiEvPtr NonRegParam(long date,short param,short val,short chan,
                      short port)
{
    MidiEvPtr e;

    if (e = MidiNewEv(typeNonRegParam))
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,param); /* Fields particular to NonRegParam */
        MidiSetField(e,1,val);
    }
    return e;
}


/#typeNote          (code 0)
_____________________________________________________________________

Event Description
A note with pitch, velocity and duration. When a Note event is sent to 
external Midi devices, actually a NoteOn message is first sent followed, 
after a delay specified by the duration, by a NoteOn with a velocity 
of 0 to end the note.


Fields : Note events have 3 fields numbered from 0 to 2 :

    0 - Pitch, a note number from 0 to 127. (Field size : 1 byte)
    1 - Vel, a note velocity from 0 to 127. (Field size : 1 byte)
    2 - Dur, a note duration from 0 to 215-1. (Field size : 2 bytes)


_____________________________________________________________________
Example 1 (ANSI C)
Creates a Note event. Return a pointer to the event or NIL if there is 
no more memory space. Fields are modified using MidiSetField instead of 
direct structure access.

MidiEvPtr Note(long date,short pitch,short vel,short duration,
               short chan, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeNote ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,pitch); /*These fields are particular to Notes*/
        MidiSetField(e,1,vel);
        MidiSetField(e,2,dur);
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Creates a Note event. Return a pointer to the event or NIL if there is 
no more memory space. Fields are modified using direct structure access 
instead of MidiSetField.

MidiEvPtr Note(long date,short pitch,short vel,short duration,
               short chan, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeNote ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;   /* These informations are common to all */
        Chan(e) = chan;   /* kind of events */
        Port(e) = port;
        Pitch(e) = pitch; /* These fields are particular to Notes */
        Vel(e)  = vel;
        Dur(e)  = dur;
    }
    return e;
}


/#typePitchWheel    (code 7)
_____________________________________________________________________

Event Description
A Pitch Bender message with a 14 bits resolution. 


Fields : PitchWheel events have 2 fields numbered from 0 to 1 :

    0 - LS 7-Bits of 14-bits pitch swing, from 0 to 127. 
        (Field size : 1 byte)
    1 - MS 7-Bits of 14-bits pitch swing, from 0 to 127. 
        (Field size : 1 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a PitchWheel  event with a parameter between -8192 and 8191. 
Return a pointer to the event or NIL if there is no more memory space.

MidiEvPtr PitchWheel( long date, short wheel, short chan, short port)
{
    const offset = 8192;
    const min = -8192;
    const max = 8191;
    MidiEvPtr e;

    wheel = (wheel>max) ? max : (wheel<min) ? min : wheel;

    if ( e = MidiNewEv( typePitchWheel ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,(wheel+offset) & 0x7F);    /*LS-7bits Field*/
        MidiSetField(e,1,(wheel+offset)>>7 & 0x7F); /*MS-7bits Field*/
    }
    return e;
}


/#typePrivate       (code 19 to 127)
_____________________________________________________________________

Event Description
A private event with 4 fields which can be freely used by the 
application. Sends only to the application who owned it.


Fields : Private events have 4 fields numbered from 0 to 3.
         Fields size : 4 bytes.


_____________________________________________________________________
Example (ANSI C)
<to be supplied>


/#typeProcess       (code 128)
_____________________________________________________________________

Event Description
Process events are automatically created by MidiCall and MidiTask. 
They are used to realize time delayed procedure call. The procedure 
call is achieved under interrupts as soon as the scheduling date 
is due.


Fields : Process events have 4 fields numbered from 0 to 3 :

    0 - a TaskPtr, the adress of the procedure to call.
        (Field size:4 byte)
    1 - the first argument of the procedure. (Field size : 4 byte)
    2 - the second argument of the procedure. (Field size : 4 byte)
    3 - the third argument of the procedure. (Field size : 4 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a Process event in the same way than MidiTask.

MidiEvPtr MakeTask ( TaskPtr proc, long date, short refNum, long arg1,
                    long arg2, long arg3)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeProcess ) )
    /* Allocate a new event. Check not NIL */ 
    {
        MidiSetField(e, 0, (long)proc); /* Fill the 4 fields */
        MidiSetField(e, 1, arg1);
        MidiSetField(e, 2, arg2);
        MidiSetField(e, 3, arg3);
        MidiSendAt(refNum, e, date);    /* and schedule the task */
    }
    return e;
}


/#typeProgChange    (code 5)
_____________________________________________________________________

Event Description
A Program Change message with a program number. 


Fields : ProgChange events have 1 field numbered 0 :

    0 - A program number from 0 to 127. (Field size : 1 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a ProgChange event. Return a pointer to the event or NIL if 
there is no more memory space.

MidiEvPtr ProgChange( long date, short prog, short chan, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeProgChange ) )
    /* Allocate a new event. Check not NIL*/ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,prog); /* Field particular to ProgChange */
    }
    return e;
}


/#typeQuarterFrame  (code 130)
_____________________________________________________________________

Event Description
A Midi time code quarter frame message with message type and value. 
These two fields are automatically assembled by MidiShare into one byte 
when the message is sent. 

Fields : QuarterFrame events have 2 fields numbered from 0 to 1 :

    0 - A message type from 0=Frame count LSB nibble to 7=Hours 
        count MS nibble. (Field size : 1 byte)
    1 - A count nibble from 0 to 15. (Field size : 1 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a QuarterFrame event. Return a pointer to the event or NIL if 
there is no more memory space.

MidiEvPtr QuarterFrame( long date, short type, short nibble,short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeQuarterFrame ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;   /* These informations are common to all */
        Port(e) = port;   /* kind of events */
        MidiSetField(e,0,type); /* Fields particular to QuarterFrame */
        MidiSetField(e,1,nibble);
    }
    return e;
}


/#typeRegParam      (code 133)
_____________________________________________________________________

Event Description
A Registred Parameter event with a 14-bits parameter number and a 
14-bits parameter value. When a typeRegParam event is sent to external 
Midi devices, actually four control change messages are sent, two to 
select the registred parameter number, and two for the parameter value 
using the 14-bits data-entry controller.

Fields : typeRegParam events have 2 fields numbered from 0 to 1 :

    0 - A Registred Parameter number from 0 to 16383. 
        (Field size : 2 byte)
    1 - A Registerd Parameter value from 0 to 16383.  
        (Field size : 2 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a Registred Parameter event. Return a pointer to the event or 
NIL if there is no more memory space.

MidiEvPtr RegParam(long date,short param,short val,short chan,
                   short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeRegParam ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,param); /* Fields particular to RegParam */
        MidiSetField(e,1,val);
    }
    return e;
}


/#typeReserved      (code 149 to 254)
_____________________________________________________________________

Event Description

These events are reserved for future use. 


/#typeReset         (code 16)
_____________________________________________________________________

Event Description
A Real Time Reset message. 


Fields : Reset events have no field.


_____________________________________________________________________
Example (ANSI C)
Creates a Reset event. Return a pointer to the event or NIL if there 
is no more memory space.

MidiEvPtr Reset ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeReset ) )
    /* Allocate a new event. Check not NIL*/ 
    {
        Date(e) = date;  /* These informations are common to all */
        Port(e) = port;  /* kind of events */
    }
    return e;
}


/#typeSeqName       (code 137)
_____________________________________________________________________

Event Description
A sequence name event (from the MidiFile 1.0 specification). This event 
cannot be sent to external Midi devices.


Fields : typeSeqName events have a variable number of character fields. 


_____________________________________________________________________
Example 1 (ANSI C)
Creates a typeSeqName event from a character string. Return a pointer 
to the event or NIL if there is not enough memory space.

MidiEvPtr SeqName ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv( typeSeqName ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++) /* Build the event while counting the*/
            MidiAddField(e ,*s);/* characters of the original string */
        if (c != MidiCountFields(e)){ /*Check the length of the event*/
            MidiFreeEv(e);      /* if we run out of memory : free the*/
            return 0;           /* event and return NIL */
        }
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Convert a typeSeqName event into a character string. Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;
    
    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}


/#typeSeqNum        (code 134)
_____________________________________________________________________

Event Description
A Sequence number event (form the MidiFile 1.0 specification). 
This event cannot be sent to external Midi devices. 


Fields : typeSeqNum events have 1 field :

    0 - Sequence number form 0 to 65535 (2-bytes field)


_____________________________________________________________________
Example (ANSI C)
Creates a Sequence Number event. Return a pointer to the event or NIL 
if there is no more memory space.

MidiEvPtr SeqNum( long date, short num, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeSeqNum) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;    /* These informations are common to all */
        Port(e) = port;    /* kind of events */
        MidiSetField(e,0,num); /* the sequence number field */
    }
    return e;
}


/#typeSMPTEOffset   (code 145)
_____________________________________________________________________

Event Description
An SMPTE Offset event (form the MidiFile 1.0 specification). This event 
cannot be sent to external Midi devices. 


Fields : typeSMPTEOffset events have 2 fields :

    0 - Hours, minutes and seconds parts of the SMPTE Offset in seconds 
        from 0 to 1048575 (20-bits field)
    1 - Frames and 100ths of a frame part of the SMPTE Offset in 100ths 
        of a frame form 0 to 4095 (12-bits field)


_____________________________________________________________________
Example 1 (ANSI C)
Creates an SMPTE Offset event. Return a pointer to the event or NIL if 
there is no more memory space.

MidiEvPtr SMPTEOffset(long hr,long mn,long sec,long frames,
                      long subframes)
{
    MidiEvPtr e;

    if (e = MidiNewEv(typeSMPTEOffset))
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = 0;
        MidiSetField(e, 0, hr*3600 + mn*60 + sec);
        MidiSetField(e, 1, (frames*100 + subframes));
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Read the different parts of an SMPTE Offset event. 

long GetHours (MidiEvPtr e)
{
    return MidiGetField(e,0) / 3600;
}

long GetMinutes (MidiEvPtr e)
{
    return MidiGetField(e,0) % 3600 / 60;
}

long GetSeconds (MidiEvPtr e)
{
    return MidiGetField(e,0) % 60;
}

long GetFrames (MidiEvPtr e)
{
    return MidiGetField(e,1) / 100;
}

long GetSubFrames (MidiEvPtr e)
{
    return MidiGetField(e,1) % 100;
}


/#typeSongPos       (code 8)
_____________________________________________________________________

Event Description
A Song Position Pointer message with a 14 bits location 
(unit : 6 Midi Clocks). 

Fields : SongPos events have 2 fields numbered from 0 to 1 :

    0 - LS 7-Bits of 14-bits location, from 0 to 127. 
        (Field size : 1 byte)
    1 - MS 7-Bits of 14-bits location, from 0 to 127. 
        (Field size : 1 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a SongPos  event with a location in Midi clocks. The location 
is internaly divided by 6. Return a pointer to the event or NIL if 
there is no more memory space.

MidiEvPtr SongPos( long date, short pos, short port)
{
    MidiEvPtr e;

    pos = pos / 6;

    if ( e = MidiNewEv( typeSongPos) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;    /* These informations are common to all */
        Port(e) = port;    /* kind of events */
        MidiSetField(e,0,pos & 0x7F);    /* LS-7bits Field */
        MidiSetField(e,1,pos>>7 & 0x7F); /* MS-7bits Field */
    }
    return e;
}


/#typeSongSel       (code 9)
_____________________________________________________________________

Event Description
A Song Select message with a song number. 


Fields : SongSel events have 1 field numbered 0 :

    0 - A song number from 0 to 127. (Field size : 1 byte)


_____________________________________________________________________
Example (ANSI C)
Creates a SongSel event. Return a pointer to the event or NIL if there 
is no more memory space.

MidiEvPtr SongSel ( long date, short song, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeSongSel ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;    /* These informations are common to all */
        Port(e) = port;    /* kind of events */
        MidiSetField(e,0,song); /* Field particular to SongSel */
    }
    return e;
}


/#typeSpecific      (code 148)
_____________________________________________________________________

Event Description
A sequencer specific event (from the MidiFile 1.0 specification). This 
event cannot be sent to external Midi devices.


Fields : typeSpecific events have a variable number of 8-bits fields. 


_____________________________________________________________________
Example (ANSI C)
Creates a typeSpecific event from an array of bytes. Return a pointer 
to the event or NIL if there is no more memory space.

MidiEvPtr Specific ( long date, short len, Byte *p)
{
    MidiEvPtr e;
    short    c;

    if ( e = MidiNewEv( typeStream ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;
        c = len;
        while (c--) MidiAddField(e,*p++);
        if (MidiCountFields(e) < len ) /*if event smaller than len then*/
        {
            MidiFreeEv(e);  /* we run out of memory, free it */
            e = nil;        /* and return nil */
        }
    }
    return e;
}


/#typeStart         (code 11)
_____________________________________________________________________

Event Description
A Real Time Start message. 


Fields : Start events have no field.


_____________________________________________________________________
Example (ANSI C)
Creates a Start event. Return a pointer to the event or NIL if there 
is no more memory space.

MidiEvPtr Start ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeStart ) )
    /* Allocate a new event. Check not NIL*/ 
    {
        Date(e) = date;   /* These informations are common to all */
        Port(e) = port;   /* kind of events */
    }
    return e;
}


/#typeStop          (code 13)
_____________________________________________________________________

Event Description
A Real Time Stop message. 


Fields : Stop events have no field.


_____________________________________________________________________
Example (ANSI C)
Creates a Stop event. Return a pointer to the event or NIL if there is 
no more memory space.

MidiEvPtr Stop ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeStop ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;  /* These informations are common to all */
        Port(e) = port;  /* kind of events */
    }
    return e;
}


/#typeStream        (code 18)
_____________________________________________________________________

Event Description
Stream message are arbitrary stream of bytes sent by the MidiShare 
driver without any processing. 


Fields : Stream events have a variable number of fields. 


_____________________________________________________________________
Example (ANSI C)
Creates a Stream event from an array of short. Return a pointer to the 
event or NIL if there is no more memory space.

MidiEvPtr Stream ( long date, short len, short *p, short port)
{
    MidiEvPtr e;
    short c;

    if ( e = MidiNewEv( typeStream ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;   /* These informations are common to all */
        Port(e) = port;   /* kind of events */
        c = len+1;
        while (--c) MidiAddField(e,*p++);
        if (MidiCountFields(e) < len ) /* if event smaller than len then*/
        {
            MidiFreeEv(e);   /* we run out of memory, free it */
            e = nil;         /* and return nil */
        }
    }
    return e;
}


/#typeSysEx         (code 17)
_____________________________________________________________________

Event Description
A System Exclusive message. 


Fields : SysEx events have a variable number of fields. The leading F0 
and tailing F7 codes must not be included. They are automatically 
supplied by MidiShare. The channel field of the event is ORed with the 
first data byte after the manufacturer ID. This works for setting the 
channel of many system exclusive messages.


_____________________________________________________________________
Example (ANSI C)
Creates a SysEx event from an array of short. Return a pointer to the 
event or NIL if there is no more memory space.

MidiEvPtr SysEx ( long date, short len, short *p, short chan, 
                  short port)
{
    MidiEvPtr e;
    short c;

    if ( e = MidiNewEv( typeSysEx ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        c = len+1;
        while (--c) MidiAddField(e,*p++);
        if (MidiCountFields(e) < len ) /* if event smaller than len then*/
        {
            MidiFreeEv(e);   /* we run out of memory, free it */
            e = nil;         /* and return nil */
        }
    }
    return e;
}


/#typeTempo         (code 144)
_____________________________________________________________________

Event Description
A tempo event (from the MidiFile 1.0 specification). This event cannot 
be sent to external Midi devices.


Fields : typeTempo  events have one field.

     0 - A tempo value in microseconds/Midi quarter-note 0 to 127. 
         (Field size : 4 bytes)


_____________________________________________________________________
Example 1 (ANSI C)
Creates a typeTempo event from a floating point tempo value in 
quarter-notes per minutes. Return a pointer to the event or NIL if 
there is not enough memory space.

MidiEvPtr TempoChange ( long date, float tempo)
{
    MidiEvPtr e;

    if ( e = MidiNewEv(typeTempo))
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;
        MidiSetField(e, 0, (long)(60000000.0 / tempo));
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Convert a tempo event in microseconds per quarter-note in a floating 
point tempo value in quarter-notes per minutes.

float GetTempo (MidiEvPtr e)
{
    return 60000000.0 / (float) MidiGetField(e,0);
}


/#typeText          (code 135)
_____________________________________________________________________

Event Description
A text event (from the MidiFile 1.0 specification). This event cannot 
be sent to external Midi devices.


Fields : typeText events have a variable number of character fields. 


_____________________________________________________________________
Example 1 (ANSI C)
Creates a typeText event from a character string. Return a pointer to 
the event or NIL if there is not enough memory space.

MidiEvPtr Text ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv( typeText ) )
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++)  /* Build the text event while counting  */
            MidiAddField(e ,*s); /* the characters of the original string */
        if (c != MidiCountFields(e)){/* Check the length of the text event*/
            MidiFreeEv(e);    /* if we run out of memory : free the */
            return 0;         /* text event and return NIL */
        }
    }
    return e;
}


_____________________________________________________________________
Example 2 (ANSI C)
Convert a typeText event into a character string. Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;
    
    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}


/#typeTimeSign      (code 146)
_____________________________________________________________________

Event Description
A Time Signature event (form the MidiFile 1.0 specification). This 
event cannot be sent to external Midi devices. 


Fields : typeTimeSign events have 4 fields :

    0 - Numerator (8-bits field)
    1 - denominator in power of two (8-bits field)
    2 - Midi Clocks per metronome clicks (8-bits field)
    3 - notated 32th of note per quarter-note (8-bits field)


_____________________________________________________________________
Example (ANSI C)
Creates a Time Signature event. Return a pointer to the event or NIL 
if there is no more memory space.

MidiEvPtr TimeSign (long date, long num, long denom, long click, 
                    long quarterDef)
{
    MidiEvPtr e;

    if ( e = MidiNewEv(typeTimeSign))
    /* Allocate a new event. Check not NIL */ 
    {
        Date(e) = date;
        MidiSetField(e, 0, num);
        MidiSetField(e, 1, denom);
        MidiSetField(e, 2, click);
        MidiSetField(e, 3, quarterDef);
    }
    return e;
}


/#typeTune          (code 14)
_____________________________________________________________________

Event Description
A Tune message. 


Fields : Tune events have no field.


_____________________________________________________________________
Example (ANSI C)
Creates a Tune event. Return a pointer to the event or NIL if there is 
no more memory space.

MidiEvPtr Tune ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeTune ) )
    /* Allocate a new event. Check not NIL*/ 
    {
        Date(e) = date;  /* These informations are common to all */
        Port(e) = port;  /* kind of events */
    }
    return e;
}



/~STRUCTURES

/#MidiSEXPtr
_____________________________________________________________________

typedef struct TMidiSEX *MidiSEXPtr;

typedef struct TMidiSEX
{
    MidiSEXPtr link;   /* link to next cell */
    Byte data[12];     /* 12 data bytes     */
} TMidiSEX;


/#MidiSTPtr
_____________________________________________________________________

typedef struct TMidiST *MidiSTPtr;

typedef struct TMidiST
{
    Ptr ptr1;   /* 4 32-bits fields */
    Ptr ptr2;
    Ptr ptr3;
    Ptr ptr4;
} TMidiST;


/#MidiEvPtr
_____________________________________________________________________

typedef struct TMidiEv *MidiEvPtr;

typedef struct TMidiEv
{
    MidiEvPtr link;       /* link to next event      */
    unsigned long date;   /* event date (in ms)      */
    Byte evType;          /* event type              */
    Byte refNum;          /* sender reference number */
    Byte port;            /* Midi port               */
    Byte chan;            /* Midi channel            */
    union {               /* info depending of event type : */
        struct {              /* for notes    */
            Byte pitch;           /* pitch    */
            Byte vel;             /* velocity */
            unsigned short dur;   /* duration */
        } note;

        struct {              /* for MidiFile time signature  */
            Byte numerator;       /* numerator                */
            Byte denominator;     /* denominator as neg power */
                                  /* of 2. (2= quarter note)  */
            Byte nClocks;         /* number of Midi clocks in */
                                  /* a metronome click        */
            Byte n32nd;           /* number of 32nd notes in  */
                                  /* a Midi quarter note      */
        } timeSign;

        struct {              /* for MidiFile key signature */
            char ton;             /* 0: key of C, 1: 1 sharp */
                                  /* -1: 1 flat etc...       */
            Byte mode;            /* 0: major 1: minor       */
            Byte unused[2];
        } keySign;

        struct {              /* for MidiFile sequence number */
            unsigned short number;
            short unused;
        } seqNum;
        long tempo;            /* MidiFile tempo in            */
                               /* microsec/Midi quarter note   */
        Byte data[4];          /* for other small events       */
        MidiSEXPtr linkSE;     /* link to last sysex extension */
        MidiSTPtr linkST;      /* link to private extension    */
    } info;
} TMidiEv;


/#MidiSeqPtr
_____________________________________________________________________

typedef struct TMidiSeq *MidiSeqPtr;

typedef struct TMidiSeq
{
    MidiEvPtr first;   /* first event pointer */
    MidiEvPtr last;    /* last event pointer  */
    Ptr undef1;
    Ptr undef2;
} TMidiSeq;


/#FilterPtr
_____________________________________________________________________

typedef struct TFilter *FilterPtr;

typedef struct TFilter
{
    char port[32];      /* 256 bits */
    char evType[32];    /* 256 bits */
    char channel[2];    /*  16 bits */
    char unused[2];     /*  16 bits */
} TFilter; 


/#SyncInfoPtr
_____________________________________________________________________

typedef struct TSyncInfo *SyncInfoPtr;

typedef struct TSyncInfo
{
    long        time;
    long        reenter;
    unsigned short syncMode;
    Byte        syncLocked; 
    Byte        syncPort;
    long        syncStart;
    long        syncStop;
    long        syncOffset;
    long        syncSpeed;
    long        syncBreaks;
    short       syncFormat;
} TSyncInfo; 


/#SmpteLocPtr
_____________________________________________________________________

typedef struct TSmpteLocation *SmpteLocPtr;

typedef struct TSmpteLocation
{
    short format;    // (0:24f/s, 1:25f/s, 2:30DFf/s, 3:30f/s)
    short hours;     // 0..23
    short minutes;   // 0..59
    short seconds;   // 0..59
    short frames;    // 0..30 (according to format)
    short fracs;     // 0..99 (1/100 of frames)
} TSmpteLocation; 
